parent
10af945f36
commit
625264b6d8
@ -0,0 +1,203 @@ |
|||||||
|
package com.jme3.input.ios; |
||||||
|
|
||||||
|
import com.jme3.input.RawInputListener; |
||||||
|
import com.jme3.input.TouchInput; |
||||||
|
import com.jme3.input.event.InputEvent; |
||||||
|
import com.jme3.input.event.KeyInputEvent; |
||||||
|
import com.jme3.input.event.MouseButtonEvent; |
||||||
|
import com.jme3.input.event.MouseMotionEvent; |
||||||
|
import com.jme3.input.event.TouchEvent; |
||||||
|
import com.jme3.system.AppSettings; |
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
public class IosInputHandler implements TouchInput { |
||||||
|
private static final Logger logger = Logger.getLogger(IosInputHandler.class.getName()); |
||||||
|
|
||||||
|
private final static int MAX_TOUCH_EVENTS = 1024; |
||||||
|
|
||||||
|
// Custom settings
|
||||||
|
private boolean mouseEventsEnabled = true; |
||||||
|
private boolean mouseEventsInvertX = false; |
||||||
|
private boolean mouseEventsInvertY = false; |
||||||
|
private boolean keyboardEventsEnabled = false; |
||||||
|
private boolean dontSendHistory = false; |
||||||
|
|
||||||
|
// Internal
|
||||||
|
private boolean initialized = false; |
||||||
|
private RawInputListener listener = null; |
||||||
|
private ConcurrentLinkedQueue<InputEvent> inputEventQueue = new ConcurrentLinkedQueue<InputEvent>(); |
||||||
|
private final TouchEventPool touchEventPool = new TouchEventPool(MAX_TOUCH_EVENTS); |
||||||
|
private IosTouchHandler touchHandler; |
||||||
|
private float scaleX = 1f; |
||||||
|
private float scaleY = 1f; |
||||||
|
private int width = 0; |
||||||
|
private int height = 0; |
||||||
|
|
||||||
|
public IosInputHandler() { |
||||||
|
touchHandler = new IosTouchHandler(this); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void initialize() { |
||||||
|
touchEventPool.initialize(); |
||||||
|
if (touchHandler != null) { |
||||||
|
touchHandler.initialize(); |
||||||
|
} |
||||||
|
initialized = true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void update() { |
||||||
|
logger.log(Level.FINE, "InputEvent update : {0}", |
||||||
|
new Object[]{listener}); |
||||||
|
if (listener != null) { |
||||||
|
InputEvent inputEvent; |
||||||
|
|
||||||
|
while ((inputEvent = inputEventQueue.poll()) != null) { |
||||||
|
if (inputEvent instanceof TouchEvent) { |
||||||
|
listener.onTouchEvent((TouchEvent)inputEvent); |
||||||
|
} else if (inputEvent instanceof MouseButtonEvent) { |
||||||
|
listener.onMouseButtonEvent((MouseButtonEvent)inputEvent); |
||||||
|
} else if (inputEvent instanceof MouseMotionEvent) { |
||||||
|
listener.onMouseMotionEvent((MouseMotionEvent)inputEvent); |
||||||
|
} else if (inputEvent instanceof KeyInputEvent) { |
||||||
|
listener.onKeyEvent((KeyInputEvent)inputEvent); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void destroy() { |
||||||
|
initialized = false; |
||||||
|
touchEventPool.destroy(); |
||||||
|
if (touchHandler != null) { |
||||||
|
touchHandler.destroy(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isInitialized() { |
||||||
|
return initialized; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setInputListener(RawInputListener listener) { |
||||||
|
this.listener = listener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getInputTimeNanos() { |
||||||
|
return System.nanoTime(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setSimulateMouse(boolean simulate) { |
||||||
|
this.mouseEventsEnabled = simulate; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean getSimulateMouse() { |
||||||
|
return mouseEventsEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean isSimulateMouse() { |
||||||
|
return mouseEventsEnabled; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setSimulateKeyboard(boolean simulate) { |
||||||
|
this.keyboardEventsEnabled = simulate; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setOmitHistoricEvents(boolean dontSendHistory) { |
||||||
|
this.dontSendHistory = dontSendHistory; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void showVirtualKeyboard(boolean visible) { |
||||||
|
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
|
||||||
|
} |
||||||
|
|
||||||
|
// ----------------
|
||||||
|
|
||||||
|
public void loadSettings(AppSettings settings) { |
||||||
|
// TODO: add simulate keyboard to settings
|
||||||
|
// keyboardEventsEnabled = true;
|
||||||
|
mouseEventsEnabled = true;//settings.isEmulateMouse();
|
||||||
|
mouseEventsInvertX = settings.isEmulateMouseFlipX(); |
||||||
|
mouseEventsInvertY = settings.isEmulateMouseFlipY(); |
||||||
|
|
||||||
|
// view width and height are 0 until the view is displayed on the screen
|
||||||
|
//if (view.getWidth() != 0 && view.getHeight() != 0) {
|
||||||
|
// scaleX = (float)settings.getWidth() / (float)view.getWidth();
|
||||||
|
// scaleY = (float)settings.getHeight() / (float)view.getHeight();
|
||||||
|
//}
|
||||||
|
scaleX = 1.0f; |
||||||
|
scaleY = 1.0f; |
||||||
|
width = settings.getWidth(); |
||||||
|
height = settings.getHeight(); |
||||||
|
logger.log(Level.FINE, "Setting input scaling, scaleX: {0}, scaleY: {1}, width: {2}, height: {3}", |
||||||
|
new Object[]{scaleX, scaleY, width, height}); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isMouseEventsInvertX() { |
||||||
|
return mouseEventsInvertX; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isMouseEventsInvertY() { |
||||||
|
return mouseEventsInvertY; |
||||||
|
} |
||||||
|
|
||||||
|
public float invertX(float origX) { |
||||||
|
return getJmeX(width) - origX; |
||||||
|
} |
||||||
|
|
||||||
|
public float invertY(float origY) { |
||||||
|
return getJmeY(height) - origY; |
||||||
|
} |
||||||
|
|
||||||
|
public float getJmeX(float origX) { |
||||||
|
return origX * scaleX; |
||||||
|
} |
||||||
|
|
||||||
|
public float getJmeY(float origY) { |
||||||
|
return origY * scaleY; |
||||||
|
} |
||||||
|
|
||||||
|
public TouchEvent getFreeTouchEvent() { |
||||||
|
return touchEventPool.getNextFreeEvent(); |
||||||
|
} |
||||||
|
|
||||||
|
public void addEvent(InputEvent event) { |
||||||
|
inputEventQueue.add(event); |
||||||
|
if (event instanceof TouchEvent) { |
||||||
|
touchEventPool.storeEvent((TouchEvent)event); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// ----------------
|
||||||
|
|
||||||
|
public void injectTouchDown(int pointerId, long time, float x, float y) { |
||||||
|
logger.log(Level.FINE, "Using input scaling, scaleX: {0}, scaleY: {1}, width: {2}, height: {3}", |
||||||
|
new Object[]{scaleX, scaleY, width, height}); |
||||||
|
if (touchHandler != null) { |
||||||
|
touchHandler.actionDown(pointerId, time, x, y); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void injectTouchUp(int pointerId, long time, float x, float y) { |
||||||
|
if (touchHandler != null) { |
||||||
|
touchHandler.actionUp(pointerId, time, x, y); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void injectTouchMove(int pointerId, long time, float x, float y) { |
||||||
|
if (touchHandler != null) { |
||||||
|
touchHandler.actionMove(pointerId, time, x, y); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,191 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.jme3.input.ios; |
||||||
|
|
||||||
|
import com.jme3.input.event.InputEvent; |
||||||
|
import com.jme3.input.event.MouseButtonEvent; |
||||||
|
import com.jme3.input.event.MouseMotionEvent; |
||||||
|
import com.jme3.input.event.TouchEvent; |
||||||
|
import static com.jme3.input.event.TouchEvent.Type.DOWN; |
||||||
|
import static com.jme3.input.event.TouchEvent.Type.MOVE; |
||||||
|
import static com.jme3.input.event.TouchEvent.Type.UP; |
||||||
|
import com.jme3.math.Vector2f; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* AndroidTouchHandler is the base class that receives touch inputs from the |
||||||
|
* Android system and creates the TouchEvents for jME. This class is designed |
||||||
|
* to handle the base touch events for Android rev 9 (Android 2.3). This is |
||||||
|
* extended by other classes to add features that were introducted after |
||||||
|
* Android rev 9. |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class IosTouchHandler { |
||||||
|
private static final Logger logger = Logger.getLogger(IosTouchHandler.class.getName()); |
||||||
|
|
||||||
|
final private HashMap<Integer, Vector2f> lastPositions = new HashMap<Integer, Vector2f>(); |
||||||
|
|
||||||
|
protected int numPointers = 1; |
||||||
|
|
||||||
|
protected IosInputHandler iosInput; |
||||||
|
|
||||||
|
public IosTouchHandler(IosInputHandler iosInput) { |
||||||
|
this.iosInput = iosInput; |
||||||
|
} |
||||||
|
|
||||||
|
public void initialize() { |
||||||
|
} |
||||||
|
|
||||||
|
public void destroy() { |
||||||
|
} |
||||||
|
|
||||||
|
public void actionDown(int pointerId, long time, float x, float y) { |
||||||
|
logger.log(Level.FINE, "Inject input pointer: {0}, time: {1}, x: {2}, y: {3}", |
||||||
|
new Object[]{pointerId, time, x, y}); |
||||||
|
float jmeX = iosInput.getJmeX(x); |
||||||
|
float jmeY = iosInput.invertY(iosInput.getJmeY(y)); |
||||||
|
TouchEvent touch = iosInput.getFreeTouchEvent(); |
||||||
|
touch.set(TouchEvent.Type.DOWN, jmeX, jmeY, 0, 0); |
||||||
|
touch.setPointerId(pointerId);//TODO: pointer ID
|
||||||
|
touch.setTime(time); |
||||||
|
touch.setPressure(1.0f); |
||||||
|
//touch.setPressure(event.getPressure(pointerIndex)); //TODO: preassure
|
||||||
|
|
||||||
|
lastPositions.put(pointerId, new Vector2f(jmeX, jmeY)); |
||||||
|
|
||||||
|
processEvent(touch); |
||||||
|
} |
||||||
|
|
||||||
|
public void actionUp(int pointerId, long time, float x, float y) { |
||||||
|
float jmeX = iosInput.getJmeX(x); |
||||||
|
float jmeY = iosInput.invertY(iosInput.getJmeY(y)); |
||||||
|
TouchEvent touch = iosInput.getFreeTouchEvent(); |
||||||
|
touch.set(TouchEvent.Type.UP, jmeX, jmeY, 0, 0); |
||||||
|
touch.setPointerId(pointerId);//TODO: pointer ID
|
||||||
|
touch.setTime(time); |
||||||
|
touch.setPressure(1.0f); |
||||||
|
//touch.setPressure(event.getPressure(pointerIndex)); //TODO: preassure
|
||||||
|
lastPositions.remove(pointerId); |
||||||
|
|
||||||
|
processEvent(touch); |
||||||
|
} |
||||||
|
|
||||||
|
public void actionMove(int pointerId, long time, float x, float y) { |
||||||
|
float jmeX = iosInput.getJmeX(x); |
||||||
|
float jmeY = iosInput.invertY(iosInput.getJmeY(y)); |
||||||
|
Vector2f lastPos = lastPositions.get(pointerId); |
||||||
|
if (lastPos == null) { |
||||||
|
lastPos = new Vector2f(jmeX, jmeY); |
||||||
|
lastPositions.put(pointerId, lastPos); |
||||||
|
} |
||||||
|
|
||||||
|
float dX = jmeX - lastPos.x; |
||||||
|
float dY = jmeY - lastPos.y; |
||||||
|
if (dX != 0 || dY != 0) { |
||||||
|
TouchEvent touch = iosInput.getFreeTouchEvent(); |
||||||
|
touch.set(TouchEvent.Type.MOVE, jmeX, jmeY, dX, dY); |
||||||
|
touch.setPointerId(pointerId); |
||||||
|
touch.setTime(time); |
||||||
|
touch.setPressure(1.0f); |
||||||
|
//touch.setPressure(event.getPressure(p));
|
||||||
|
lastPos.set(jmeX, jmeY); |
||||||
|
|
||||||
|
processEvent(touch); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void processEvent(TouchEvent event) { |
||||||
|
// Add the touch event
|
||||||
|
iosInput.addEvent(event); |
||||||
|
// MouseEvents do not support multi-touch, so only evaluate 1 finger pointer events
|
||||||
|
if (iosInput.isSimulateMouse() && numPointers == 1) { |
||||||
|
InputEvent mouseEvent = generateMouseEvent(event); |
||||||
|
if (mouseEvent != null) { |
||||||
|
// Add the mouse event
|
||||||
|
iosInput.addEvent(mouseEvent); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// TODO: Ring Buffer for mouse events?
|
||||||
|
protected InputEvent generateMouseEvent(TouchEvent event) { |
||||||
|
InputEvent inputEvent = null; |
||||||
|
int newX; |
||||||
|
int newY; |
||||||
|
int newDX; |
||||||
|
int newDY; |
||||||
|
|
||||||
|
if (iosInput.isMouseEventsInvertX()) { |
||||||
|
newX = (int) (iosInput.invertX(event.getX())); |
||||||
|
newDX = (int)event.getDeltaX() * -1; |
||||||
|
} else { |
||||||
|
newX = (int) event.getX(); |
||||||
|
newDX = (int)event.getDeltaX(); |
||||||
|
} |
||||||
|
|
||||||
|
if (iosInput.isMouseEventsInvertY()) { |
||||||
|
newY = (int) (iosInput.invertY(event.getY())); |
||||||
|
newDY = (int)event.getDeltaY() * -1; |
||||||
|
} else { |
||||||
|
newY = (int) event.getY(); |
||||||
|
newDY = (int)event.getDeltaY(); |
||||||
|
} |
||||||
|
|
||||||
|
switch (event.getType()) { |
||||||
|
case DOWN: |
||||||
|
// Handle mouse down event
|
||||||
|
inputEvent = new MouseButtonEvent(0, true, newX, newY); |
||||||
|
inputEvent.setTime(event.getTime()); |
||||||
|
break; |
||||||
|
|
||||||
|
case UP: |
||||||
|
// Handle mouse up event
|
||||||
|
inputEvent = new MouseButtonEvent(0, false, newX, newY); |
||||||
|
inputEvent.setTime(event.getTime()); |
||||||
|
break; |
||||||
|
|
||||||
|
case HOVER_MOVE: |
||||||
|
case MOVE: |
||||||
|
inputEvent = new MouseMotionEvent(newX, newY, newDX, newDY, (int)event.getScaleSpan(), (int)event.getDeltaScaleSpan()); |
||||||
|
inputEvent.setTime(event.getTime()); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
return inputEvent; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,121 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2009-2012 jMonkeyEngine |
||||||
|
* All rights reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are |
||||||
|
* met: |
||||||
|
* |
||||||
|
* * Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* * Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||||
|
* may be used to endorse or promote products derived from this software |
||||||
|
* without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||||
|
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package com.jme3.input.ios; |
||||||
|
|
||||||
|
import com.jme3.input.event.TouchEvent; |
||||||
|
import com.jme3.util.RingBuffer; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* TouchEventPool provides a RingBuffer of jME TouchEvents to help with garbage |
||||||
|
* collection on Android. Each TouchEvent is stored in the RingBuffer and is |
||||||
|
* reused if the TouchEvent has been consumed. |
||||||
|
* |
||||||
|
* If a TouchEvent has not been consumed, it is placed back into the pool at the |
||||||
|
* end for later use. If a TouchEvent has been consumed, it is reused to avoid |
||||||
|
* creating lots of little objects. |
||||||
|
* |
||||||
|
* If the pool is full of unconsumed events, then a new event is created and provided. |
||||||
|
* |
||||||
|
* |
||||||
|
* @author iwgeric |
||||||
|
*/ |
||||||
|
public class TouchEventPool { |
||||||
|
private static final Logger logger = Logger.getLogger(TouchEventPool.class.getName()); |
||||||
|
private final RingBuffer<TouchEvent> eventPool; |
||||||
|
private final int maxEvents; |
||||||
|
|
||||||
|
public TouchEventPool (int maxEvents) { |
||||||
|
eventPool = new RingBuffer<TouchEvent>(maxEvents); |
||||||
|
this.maxEvents = maxEvents; |
||||||
|
} |
||||||
|
|
||||||
|
public void initialize() { |
||||||
|
TouchEvent newEvent; |
||||||
|
while (!eventPool.isEmpty()) { |
||||||
|
eventPool.pop(); |
||||||
|
} |
||||||
|
for (int i = 0; i < maxEvents; i++) { |
||||||
|
newEvent = new TouchEvent(); |
||||||
|
newEvent.setConsumed(); |
||||||
|
eventPool.push(newEvent); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void destroy() { |
||||||
|
// Clean up queues
|
||||||
|
while (!eventPool.isEmpty()) { |
||||||
|
eventPool.pop(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Fetches a touch event from the reuse pool |
||||||
|
* |
||||||
|
* @return a usable TouchEvent |
||||||
|
*/ |
||||||
|
public TouchEvent getNextFreeEvent() { |
||||||
|
TouchEvent evt = null; |
||||||
|
int curSize = eventPool.size(); |
||||||
|
while (curSize > 0) { |
||||||
|
evt = (TouchEvent)eventPool.pop(); |
||||||
|
if (evt.isConsumed()) { |
||||||
|
break; |
||||||
|
} else { |
||||||
|
eventPool.push(evt); |
||||||
|
evt = null; |
||||||
|
} |
||||||
|
curSize--; |
||||||
|
} |
||||||
|
|
||||||
|
if (evt == null) { |
||||||
|
logger.warning("eventPool full of unconsumed events"); |
||||||
|
evt = new TouchEvent(); |
||||||
|
} |
||||||
|
return evt; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Stores the TouchEvent back in the pool for later reuse. It is only reused |
||||||
|
* if the TouchEvent has been consumed. |
||||||
|
* |
||||||
|
* @param event TouchEvent to store for later use if consumed. |
||||||
|
*/ |
||||||
|
public void storeEvent(TouchEvent event) { |
||||||
|
if (eventPool.size() < maxEvents) { |
||||||
|
eventPool.push(event); |
||||||
|
} else { |
||||||
|
logger.warning("eventPool full"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
package com.jme3.util; |
||||||
|
|
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.NoSuchElementException; |
||||||
|
|
||||||
|
/** |
||||||
|
* Ring buffer (fixed size queue) implementation using a circular array (array |
||||||
|
* with wrap-around). |
||||||
|
*/ |
||||||
|
// suppress unchecked warnings in Java 1.5.0_6 and later
|
||||||
|
@SuppressWarnings("unchecked") |
||||||
|
public class RingBuffer<T> implements Iterable<T> { |
||||||
|
|
||||||
|
private T[] buffer; // queue elements
|
||||||
|
private int count = 0; // number of elements on queue
|
||||||
|
private int indexOut = 0; // index of first element of queue
|
||||||
|
private int indexIn = 0; // index of next available slot
|
||||||
|
|
||||||
|
// cast needed since no generic array creation in Java
|
||||||
|
public RingBuffer(int capacity) { |
||||||
|
buffer = (T[]) new Object[capacity]; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isEmpty() { |
||||||
|
return count == 0; |
||||||
|
} |
||||||
|
|
||||||
|
public int size() { |
||||||
|
return count; |
||||||
|
} |
||||||
|
|
||||||
|
public void push(T item) { |
||||||
|
if (count == buffer.length) { |
||||||
|
throw new RuntimeException("Ring buffer overflow"); |
||||||
|
} |
||||||
|
buffer[indexIn] = item; |
||||||
|
indexIn = (indexIn + 1) % buffer.length; // wrap-around
|
||||||
|
count++; |
||||||
|
} |
||||||
|
|
||||||
|
public T pop() { |
||||||
|
if (isEmpty()) { |
||||||
|
throw new RuntimeException("Ring buffer underflow"); |
||||||
|
} |
||||||
|
T item = buffer[indexOut]; |
||||||
|
buffer[indexOut] = null; // to help with garbage collection
|
||||||
|
count--; |
||||||
|
indexOut = (indexOut + 1) % buffer.length; // wrap-around
|
||||||
|
return item; |
||||||
|
} |
||||||
|
|
||||||
|
public Iterator<T> iterator() { |
||||||
|
return new RingBufferIterator(); |
||||||
|
} |
||||||
|
|
||||||
|
// an iterator, doesn't implement remove() since it's optional
|
||||||
|
private class RingBufferIterator implements Iterator<T> { |
||||||
|
|
||||||
|
private int i = 0; |
||||||
|
|
||||||
|
public boolean hasNext() { |
||||||
|
return i < count; |
||||||
|
} |
||||||
|
|
||||||
|
public void remove() { |
||||||
|
throw new UnsupportedOperationException(); |
||||||
|
} |
||||||
|
|
||||||
|
public T next() { |
||||||
|
if (!hasNext()) { |
||||||
|
throw new NoSuchElementException(); |
||||||
|
} |
||||||
|
return buffer[i++]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue