Merge branch 'master' of https://github.com/cocos2d/cocos2d-x into 439

Conflicts:
	cocos2dx/platform/ios/CCFileUtils_ios.mm
This commit is contained in:
yangws 2011-03-30 11:05:23 +08:00
commit 7e81c56231
36 changed files with 860 additions and 2375 deletions

View File

@ -8,4 +8,4 @@
# project structure.
# Project target.
target=android-8
target=android-7

View File

@ -1,2 +1,4 @@
# it is needed for ndk-r5
APP_STL := stlport_static
APP_STL := stlport_static
APP_MODULES := cocos2d cocosdenshion helloworld

View File

@ -1,119 +1,139 @@
package org.cocos2dx.lib;
import org.cocos2dx.lib.touch.metalev.multitouch.controller.MultiTouchController;
import org.cocos2dx.lib.touch.metalev.multitouch.controller.MultiTouchController.MultiTouchObjectCanvas;
import org.cocos2dx.lib.touch.metalev.multitouch.controller.MultiTouchController.PointInfo;
import org.cocos2dx.lib.touch.metalev.multitouch.controller.MultiTouchController.PositionAndScale;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.Log;
import android.view.MotionEvent;
public class Cocos2dxGLSurfaceView extends GLSurfaceView implements
MultiTouchObjectCanvas {
public class Cocos2dxGLSurfaceView extends GLSurfaceView{
private static final String TAG = Cocos2dxGLSurfaceView.class
.getCanonicalName();
private MultiTouchController<Void> mTouchController;
private Cocos2dxRenderer mRenderer;
private final boolean debug = false;
public Cocos2dxGLSurfaceView(Context context) {
super(context);
mRenderer = new Cocos2dxRenderer();
setRenderer(mRenderer);
mTouchController = new MultiTouchController<Void>(this);
}
public boolean onTouchEvent(final MotionEvent event) {
if (mTouchController.onTouchEvent(event)) {
final PointInfo pt = mTouchController.mCurrPt;
final int ids[] = new int[pt.getNumTouchPoints()];
final float xs[] = new float[pt.getNumTouchPoints()];
final float ys[] = new float[pt.getNumTouchPoints()];
// these data are used in ACTION_MOVE and ACTION_CANCEL
final int pointerNumber = event.getPointerCount();
final int[] ids = new int[pointerNumber];
final float[] xs = new float[pointerNumber];
final float[] ys = new float[pointerNumber];
for (int i = 0; i < pt.getNumTouchPoints(); i++) {
ids[i] = pt.getPointerIds()[i];
xs[i] = pt.getXs()[i];
ys[i] = pt.getYs()[i];
Log.d(TAG,
"ACTION: " + pt.getAction() + "id[i]="
+ pt.getPointerIds()[i] + "x[i]= "
+ pt.getXs()[i] + " y[i]= " + pt.getYs()[i]);
}
switch (pt.getAction()) {
case MotionEvent.ACTION_DOWN:
case 261:
case MotionEvent.ACTION_POINTER_DOWN:
Log.d(TAG, "ACTION_DOWN");
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionDown(ids, xs, ys);
}
});
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "ACTION_MOVE");
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionMove(ids, xs, ys);
}
});
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
Log.d(TAG, "ACTION_UP");
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionUp(ids, xs, ys);
}
});
break;
case MotionEvent.ACTION_CANCEL:
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionCancel(ids, xs, ys);
}
});
break;
}
return true;
for (int i = 0; i < pointerNumber; i++) {
ids[i] = event.getPointerId(i);
xs[i] = event.getX(i);
ys[i] = event.getY(i);
}
return false;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
final int idPointerDown = event.getAction() >> MotionEvent.ACTION_POINTER_ID_SHIFT;
final float xPointerDown = event.getX(idPointerDown);
final float yPointerDown = event.getY(idPointerDown);
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionDown(idPointerDown, xPointerDown, yPointerDown);
}
});
break;
case MotionEvent.ACTION_DOWN:
// there are only one finger on the screen
final int idDown = event.getPointerId(0);
final float xDown = event.getX(idDown);
final float yDown = event.getY(idDown);
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionDown(idDown, xDown, yDown);
}
});
break;
case MotionEvent.ACTION_MOVE:
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionMove(ids, xs, ys);
}
});
break;
case MotionEvent.ACTION_POINTER_UP:
final int idPointerUp = event.getAction() >> MotionEvent.ACTION_POINTER_ID_SHIFT;
final float xPointerUp = event.getX(idPointerUp);
final float yPointerUp = event.getY(idPointerUp);
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionUp(idPointerUp, xPointerUp, yPointerUp);
}
});
break;
case MotionEvent.ACTION_UP:
// there are only one finger on the screen
final int idUp = event.getPointerId(0);
final float xUp = event.getX(idUp);
final float yUp = event.getY(idUp);
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionUp(idUp, xUp, yUp);
}
});
break;
case MotionEvent.ACTION_CANCEL:
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionCancel(ids, xs, ys);
}
});
break;
}
if (debug){
dumpEvent(event);
}
return true;
}
@Override
public Object getDraggableObjectAtPoint(PointInfo touchPoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public void getPositionAndScale(Object obj,
PositionAndScale objPosAndScaleOut) {
// TODO Auto-generated method stub
}
@Override
public boolean setPositionAndScale(Object obj,
PositionAndScale newObjPosAndScale, PointInfo touchPoint) {
// TODO Auto-generated method stub
return false;
}
@Override
public void selectObject(Object obj, PointInfo touchPoint) {
// TODO Auto-generated method stub
/** Show an event in the LogCat view, for debugging */
private void dumpEvent(MotionEvent event) {
String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" ,
"POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_" ).append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
sb.append("(pid " ).append(
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")" );
}
sb.append("[" );
for (int i = 0; i < event.getPointerCount(); i++) {
sb.append("#" ).append(i);
sb.append("(pid " ).append(event.getPointerId(i));
sb.append(")=" ).append((int) event.getX(i));
sb.append("," ).append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";" );
}
sb.append("]" );
Log.d(TAG, sb.toString());
}
}

View File

@ -39,12 +39,12 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
last = now;
}
public void handleActionDown(int[] id, float[] x, float[] y)
public void handleActionDown(int id, float x, float y)
{
nativeTouchesBegin(id, x, y);
}
public void handleActionUp(int[] id, float[] x, float[] y)
public void handleActionUp(int id, float x, float y)
{
nativeTouchesEnd(id, x, y);
}
@ -63,8 +63,8 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
animationInterval = (long)(interval * NANOSECONDSPERSECOND);
}
private static native void nativeTouchesBegin(int[] id, float[] x, float[] y);
private static native void nativeTouchesEnd(int[] id, float[] x, float[] y);
private static native void nativeTouchesBegin(int id, float x, float y);
private static native void nativeTouchesEnd(int id, float x, float y);
private static native void nativeTouchesMove(int[] id, float[] x, float[] y);
private static native void nativeTouchesCancel(int[] id, float[] x, float[] y);
private static native void nativeRender();

View File

@ -1,812 +0,0 @@
package org.cocos2dx.lib.touch.metalev.multitouch.controller;
/**
* MultiTouchController.java
*
* Author: Luke Hutchison (luke.hutch@mit.edu)
* Please drop me an email if you use this code so I can list your project here!
*
* Usage:
* <code>
* public class MyMTView extends View implements MultiTouchObjectCanvas<PinchWidgetType> {
*
* private MultiTouchController<PinchWidgetType> multiTouchController = new MultiTouchController<PinchWidgetType>(this);
*
* // Pass touch events to the MT controller
* public boolean onTouchEvent(MotionEvent event) {
* return multiTouchController.onTouchEvent(event);
* }
*
* // ... then implement the MultiTouchObjectCanvas interface here, see details in the comments of that interface.
* }
* </code>
*
* Changelog:
* 2010-06-09 v1.5.1 Some API changes to make it possible to selectively update or not update scale / rotation.
* Fixed anisotropic zoom. Cleaned up rotation code. Added more comments. Better var names. (LH)
* 2010-06-09 v1.4 Added ability to track pinch rotation (Mickael Despesse, author of "Face Frenzy") and anisotropic pinch-zoom (LH)
* 2010-06-09 v1.3.3 Bugfixes for Android-2.1; added optional debug info (LH)
* 2010-06-09 v1.3 Ported to Android-2.2 (handle ACTION_POINTER_* actions); fixed several bugs; refactoring; documentation (LH)
* 2010-05-17 v1.2.1 Dual-licensed under Apache and GPL licenses
* 2010-02-18 v1.2 Support for compilation under Android 1.5/1.6 using introspection (mmin, author of handyCalc)
* 2010-01-08 v1.1.1 Bugfixes to Cyanogen's patch that only showed up in more complex uses of controller (LH)
* 2010-01-06 v1.1 Modified for official level 5 MT API (Cyanogen)
* 2009-01-25 v1.0 Original MT controller, released for hacked G1 kernel (LH)
*
* Planned features:
* - Add inertia (flick-pinch-zoom or flick-scroll)
*
* Known usages:
* - Mickael Despesse's "Face Frenzy" face distortion app, to be published to the Market soon
* - Yuan Chin's fork of ADW Launcher to support multitouch
* - David Byrne's fractal viewing app Fractoid
* - mmin's handyCalc calculator
* - My own "MultiTouch Visualizer 2" in the Market
* - Formerly: The browser in cyanogenmod (and before that, JesusFreke), and other firmwares like dwang5. This usage has been
* replaced with official pinch/zoom in Maps, Browser and Gallery[3D] as of API level 5.
*
* License:
* Dual-licensed under the Apache License v2 and the GPL v2.
*/
import java.lang.reflect.Method;
import android.util.Log;
import android.view.MotionEvent;
/**
* A class that simplifies the implementation of multitouch in applications. Subclass this and read the fields here as needed in subclasses.
*
* @author Luke Hutchison
*/
public class MultiTouchController<T> {
/**
* Time in ms required after a change in event status (e.g. putting down or lifting off the second finger) before events actually do anything --
* helps eliminate noisy jumps that happen on change of status
*/
private static final long EVENT_SETTLE_TIME_INTERVAL = 20;
/**
* The biggest possible abs val of the change in x or y between multitouch events (larger dx/dy events are ignored) -- helps eliminate jumps in
* pointer position on finger 2 up/down.
*/
private static final float MAX_MULTITOUCH_POS_JUMP_SIZE = 30.0f;
/**
* The biggest possible abs val of the change in multitouchWidth or multitouchHeight between multitouch events (larger-jump events are ignored) --
* helps eliminate jumps in pointer position on finger 2 up/down.
*/
private static final float MAX_MULTITOUCH_DIM_JUMP_SIZE = 40.0f;
/** The smallest possible distance between multitouch points (used to avoid div-by-zero errors and display glitches) */
private static final float MIN_MULTITOUCH_SEPARATION = 30.0f;
/** The max number of touch points that can be present on the screen at once */
public static final int MAX_TOUCH_POINTS = 5;
/** Generate tons of log entries for debugging */
public static final boolean DEBUG = false;
// ----------------------------------------------------------------------------------------------------------------------
MultiTouchObjectCanvas<T> objectCanvas;
/** The current touch point */
public PointInfo mCurrPt;
/** The previous touch point */
private PointInfo mPrevPt;
/** Fields extracted from mCurrPt */
private float mCurrPtX, mCurrPtY, mCurrPtDiam, mCurrPtWidth, mCurrPtHeight, mCurrPtAng;
/**
* Extract fields from mCurrPt, respecting the update* fields of mCurrPt. This just avoids code duplication. I hate that Java doesn't support
* higher-order functions, tuples or multiple return values from functions.
*/
private void extractCurrPtInfo() {
// Get new drag/pinch params. Only read multitouch fields that are needed,
// to avoid unnecessary computation (diameter and angle are expensive operations).
mCurrPtX = mCurrPt.getX();
mCurrPtY = mCurrPt.getY();
mCurrPtDiam = Math.max(MIN_MULTITOUCH_SEPARATION * .71f, !mCurrXform.updateScale ? 0.0f : mCurrPt.getMultiTouchDiameter());
mCurrPtWidth = Math.max(MIN_MULTITOUCH_SEPARATION, !mCurrXform.updateScaleXY ? 0.0f : mCurrPt.getMultiTouchWidth());
mCurrPtHeight = Math.max(MIN_MULTITOUCH_SEPARATION, !mCurrXform.updateScaleXY ? 0.0f : mCurrPt.getMultiTouchHeight());
mCurrPtAng = !mCurrXform.updateAngle ? 0.0f : mCurrPt.getMultiTouchAngle();
}
// ----------------------------------------------------------------------------------------------------------------------
/** Whether to handle single-touch events/drags before multi-touch is initiated or not; if not, they are handled by subclasses */
private boolean handleSingleTouchEvents;
/** The object being dragged/stretched */
private T selectedObject = null;
/** Current position and scale of the dragged object */
private PositionAndScale mCurrXform = new PositionAndScale();
/** Drag/pinch start time and time to ignore spurious events until (to smooth over event noise) */
private long mSettleStartTime, mSettleEndTime;
/** Conversion from object coords to screen coords */
private float startPosX, startPosY;
/** Conversion between scale and width, and object angle and start pinch angle */
private float startScaleOverPinchDiam, startAngleMinusPinchAngle;
/** Conversion between X scale and width, and Y scale and height */
private float startScaleXOverPinchWidth, startScaleYOverPinchHeight;
// ----------------------------------------------------------------------------------------------------------------------
/** No touch points down. */
private static final int MODE_NOTHING = 0;
/** One touch point down, dragging an object. */
private static final int MODE_DRAG = 1;
/** Two or more touch points down, stretching/rotating an object using the first two touch points. */
private static final int MODE_PINCH = 2;
/** Current drag mode */
private int mMode = MODE_NOTHING;
// ----------------------------------------------------------------------------------------------------------------------
/** Constructor that sets handleSingleTouchEvents to true */
public MultiTouchController(MultiTouchObjectCanvas<T> objectCanvas) {
this(objectCanvas, true);
}
/** Full constructor */
public MultiTouchController(MultiTouchObjectCanvas<T> objectCanvas, boolean handleSingleTouchEvents) {
this.mCurrPt = new PointInfo();
this.mPrevPt = new PointInfo();
this.handleSingleTouchEvents = handleSingleTouchEvents;
this.objectCanvas = objectCanvas;
}
// ------------------------------------------------------------------------------------
/**
* Whether to handle single-touch events/drags before multi-touch is initiated or not; if not, they are handled by subclasses. Default: true
*/
protected void setHandleSingleTouchEvents(boolean handleSingleTouchEvents) {
this.handleSingleTouchEvents = handleSingleTouchEvents;
}
/**
* Whether to handle single-touch events/drags before multi-touch is initiated or not; if not, they are handled by subclasses. Default: true
*/
protected boolean getHandleSingleTouchEvents() {
return handleSingleTouchEvents;
}
// ------------------------------------------------------------------------------------
public static final boolean multiTouchSupported;
private static Method m_getPointerCount;
private static Method m_getPointerId;
private static Method m_getPressure;
private static Method m_getHistoricalX;
private static Method m_getHistoricalY;
private static Method m_getHistoricalPressure;
private static Method m_getX;
private static Method m_getY;
private static int ACTION_POINTER_UP = 6;
private static int ACTION_POINTER_INDEX_SHIFT = 8;
static {
boolean succeeded = false;
try {
// Android 2.0.1 stuff:
m_getPointerCount = MotionEvent.class.getMethod("getPointerCount");
m_getPointerId = MotionEvent.class.getMethod("getPointerId", Integer.TYPE);
m_getPressure = MotionEvent.class.getMethod("getPressure", Integer.TYPE);
m_getHistoricalX = MotionEvent.class.getMethod("getHistoricalX", Integer.TYPE, Integer.TYPE);
m_getHistoricalY = MotionEvent.class.getMethod("getHistoricalY", Integer.TYPE, Integer.TYPE);
m_getHistoricalPressure = MotionEvent.class.getMethod("getHistoricalPressure", Integer.TYPE, Integer.TYPE);
m_getX = MotionEvent.class.getMethod("getX", Integer.TYPE);
m_getY = MotionEvent.class.getMethod("getY", Integer.TYPE);
succeeded = true;
} catch (Exception e) {
Log.e("MultiTouchController", "static initializer failed", e);
}
multiTouchSupported = succeeded;
if (multiTouchSupported) {
// Android 2.2+ stuff (the original Android 2.2 consts are declared above,
// and these actions aren't used previous to Android 2.2):
try {
ACTION_POINTER_UP = MotionEvent.class.getField("ACTION_POINTER_UP").getInt(null);
ACTION_POINTER_INDEX_SHIFT = MotionEvent.class.getField("ACTION_POINTER_INDEX_SHIFT").getInt(null);
} catch (Exception e) {
}
}
}
// ------------------------------------------------------------------------------------
private static final float[] xVals = new float[MAX_TOUCH_POINTS];
private static final float[] yVals = new float[MAX_TOUCH_POINTS];
private static final float[] pressureVals = new float[MAX_TOUCH_POINTS];
private static final int[] pointerIds = new int[MAX_TOUCH_POINTS];
/** Process incoming touch events */
public boolean onTouchEvent(MotionEvent event) {
try {
int pointerCount = multiTouchSupported ? (Integer) m_getPointerCount.invoke(event) : 1;
if (DEBUG)
Log.i("MultiTouch", "Got here 1 - " + multiTouchSupported + " " + mMode + " " + handleSingleTouchEvents + " " + pointerCount);
if (mMode == MODE_NOTHING && !handleSingleTouchEvents && pointerCount == 1)
// Not handling initial single touch events, just pass them on
return false;
if (DEBUG)
Log.i("MultiTouch", "Got here 2");
// Handle history first (we sometimes get history with ACTION_MOVE events)
int action = event.getAction();
int histLen = event.getHistorySize() / pointerCount;
for (int histIdx = 0; histIdx <= histLen; histIdx++) {
// Read from history entries until histIdx == histLen, then read from current event
boolean processingHist = histIdx < histLen;
if (!multiTouchSupported || pointerCount == 1) {
// Use single-pointer methods -- these are needed as a special case (for some weird reason) even if
// multitouch is supported but there's only one touch point down currently -- event.getX(0) etc. throw
// an exception if there's only one point down.
if (DEBUG)
Log.i("MultiTouch", "Got here 3");
xVals[0] = processingHist ? event.getHistoricalX(histIdx) : event.getX();
yVals[0] = processingHist ? event.getHistoricalY(histIdx) : event.getY();
pressureVals[0] = processingHist ? event.getHistoricalPressure(histIdx) : event.getPressure();
} else {
// Read x, y and pressure of each pointer
if (DEBUG)
Log.i("MultiTouch", "Got here 4");
int numPointers = Math.min(pointerCount, MAX_TOUCH_POINTS);
if (DEBUG && pointerCount > MAX_TOUCH_POINTS)
Log.i("MultiTouch", "Got more pointers than MAX_TOUCH_POINTS");
for (int ptrIdx = 0; ptrIdx < numPointers; ptrIdx++) {
int ptrId = (Integer) m_getPointerId.invoke(event, ptrIdx);
pointerIds[ptrIdx] = ptrId;
// N.B. if pointerCount == 1, then the following methods throw an array index out of range exception,
// and the code above is therefore required not just for Android 1.5/1.6 but also for when there is
// only one touch point on the screen -- pointlessly inconsistent :(
xVals[ptrIdx] = (Float) (processingHist ? m_getHistoricalX.invoke(event, ptrIdx, histIdx) : m_getX.invoke(event, ptrIdx));
yVals[ptrIdx] = (Float) (processingHist ? m_getHistoricalY.invoke(event, ptrIdx, histIdx) : m_getY.invoke(event, ptrIdx));
pressureVals[ptrIdx] = (Float) (processingHist ? m_getHistoricalPressure.invoke(event, ptrIdx, histIdx) : m_getPressure
.invoke(event, ptrIdx));
}
}
// Decode event
decodeTouchEvent(pointerCount, xVals, yVals, pressureVals, pointerIds, //
/* action = */processingHist ? MotionEvent.ACTION_MOVE : action, //
/* down = */processingHist ? true : action != MotionEvent.ACTION_UP //
&& (action & ((1 << ACTION_POINTER_INDEX_SHIFT) - 1)) != ACTION_POINTER_UP //
&& action != MotionEvent.ACTION_CANCEL, //
processingHist ? event.getHistoricalEventTime(histIdx) : event.getEventTime());
}
return true;
} catch (Exception e) {
// In case any of the introspection stuff fails (it shouldn't)
Log.e("MultiTouchController", "onTouchEvent() failed", e);
return false;
}
}
private void decodeTouchEvent(int pointerCount, float[] x, float[] y, float[] pressure, int[] pointerIds, int action, boolean down, long eventTime) {
if (DEBUG)
Log.i("MultiTouch", "Got here 5 - " + pointerCount + " " + action + " " + down);
// Swap curr/prev points
PointInfo tmp = mPrevPt;
mPrevPt = mCurrPt;
mCurrPt = tmp;
// Overwrite old prev point
mCurrPt.set(pointerCount, x, y, pressure, pointerIds, action, down, eventTime);
multiTouchController();
}
// ------------------------------------------------------------------------------------
/** Start dragging/pinching, or reset drag/pinch to current point if something goes out of range */
private void anchorAtThisPositionAndScale() {
if (selectedObject == null)
return;
// Get selected object's current position and scale
objectCanvas.getPositionAndScale(selectedObject, mCurrXform);
// Figure out the object coords of the drag start point's screen coords.
// All stretching should be around this point in object-coord-space.
// Also figure out out ratio between object scale factor and multitouch
// diameter at beginning of drag; same for angle and optional anisotropic
// scale.
float currScaleInv = 1.0f / (!mCurrXform.updateScale ? 1.0f : mCurrXform.scale == 0.0f ? 1.0f : mCurrXform.scale);
extractCurrPtInfo();
startPosX = (mCurrPtX - mCurrXform.xOff) * currScaleInv;
startPosY = (mCurrPtY - mCurrXform.yOff) * currScaleInv;
startScaleOverPinchDiam = mCurrXform.scale / mCurrPtDiam;
startScaleXOverPinchWidth = mCurrXform.scaleX / mCurrPtWidth;
startScaleYOverPinchHeight = mCurrXform.scaleY / mCurrPtHeight;
startAngleMinusPinchAngle = mCurrXform.angle - mCurrPtAng;
}
/** Drag/stretch/rotate the selected object using the current touch position(s) relative to the anchor position(s). */
private void performDragOrPinch() {
// Don't do anything if we're not dragging anything
if (selectedObject == null)
return;
// Calc new position of dragged object
float currScale = !mCurrXform.updateScale ? 1.0f : mCurrXform.scale == 0.0f ? 1.0f : mCurrXform.scale;
extractCurrPtInfo();
float newPosX = mCurrPtX - startPosX * currScale;
float newPosY = mCurrPtY - startPosY * currScale;
float newScale = startScaleOverPinchDiam * mCurrPtDiam;
float newScaleX = startScaleXOverPinchWidth * mCurrPtWidth;
float newScaleY = startScaleYOverPinchHeight * mCurrPtHeight;
float newAngle = startAngleMinusPinchAngle + mCurrPtAng;
// Set the new obj coords, scale, and angle as appropriate (notifying the subclass of the change).
mCurrXform.set(newPosX, newPosY, newScale, newScaleX, newScaleY, newAngle);
boolean success = objectCanvas.setPositionAndScale(selectedObject, mCurrXform, mCurrPt);
if (!success)
; // If we could't set those params, do nothing currently
}
/**
* State-based controller for tracking switches between no-touch, single-touch and multi-touch situations. Includes logic for cleaning up the
* event stream, as events around touch up/down are noisy at least on early Synaptics sensors.
*/
private void multiTouchController() {
if (DEBUG)
Log.i("MultiTouch", "Got here 6 - " + mMode + " " + mCurrPt.getNumTouchPoints() + " " + mCurrPt.isDown() + mCurrPt.isMultiTouch());
switch (mMode) {
case MODE_NOTHING:
// Not doing anything currently
if (mCurrPt.isDown()) {
// Start a new single-point drag
selectedObject = objectCanvas.getDraggableObjectAtPoint(mCurrPt);
if (selectedObject != null) {
// Started a new single-point drag
mMode = MODE_DRAG;
objectCanvas.selectObject(selectedObject, mCurrPt);
anchorAtThisPositionAndScale();
// Don't need any settling time if just placing one finger, there is no noise
mSettleStartTime = mSettleEndTime = mCurrPt.getEventTime();
}
}
break;
case MODE_DRAG:
// Currently in a single-point drag
if (!mCurrPt.isDown()) {
// First finger was released, stop dragging
mMode = MODE_NOTHING;
objectCanvas.selectObject((selectedObject = null), mCurrPt);
} else if (mCurrPt.isMultiTouch()) {
// Point 1 was already down and point 2 was just placed down
mMode = MODE_PINCH;
// Restart the drag with the new drag position (that is at the midpoint between the touchpoints)
anchorAtThisPositionAndScale();
// Need to let events settle before moving things, to help with event noise on touchdown
mSettleStartTime = mCurrPt.getEventTime();
mSettleEndTime = mSettleStartTime + EVENT_SETTLE_TIME_INTERVAL;
} else {
// Point 1 is still down and point 2 did not change state, just do single-point drag to new location
if (mCurrPt.getEventTime() < mSettleEndTime) {
// Ignore the first few events if we just stopped stretching, because if finger 2 was kept down while
// finger 1 is lifted, then point 1 gets mapped to finger 2. Restart the drag from the new position.
anchorAtThisPositionAndScale();
} else {
// Keep dragging, move to new point
performDragOrPinch();
}
}
break;
case MODE_PINCH:
// Two-point pinch-scale/rotate/translate
if (!mCurrPt.isMultiTouch() || !mCurrPt.isDown()) {
// Dropped one or both points, stop stretching
if (!mCurrPt.isDown()) {
// Dropped both points, go back to doing nothing
mMode = MODE_NOTHING;
objectCanvas.selectObject((selectedObject = null), mCurrPt);
} else {
// Just dropped point 2, downgrade to a single-point drag
mMode = MODE_DRAG;
// Restart the pinch with the single-finger position
anchorAtThisPositionAndScale();
// Ignore the first few events after the drop, in case we dropped finger 1 and left finger 2 down
mSettleStartTime = mCurrPt.getEventTime();
mSettleEndTime = mSettleStartTime + EVENT_SETTLE_TIME_INTERVAL;
}
} else {
// Still pinching
if (Math.abs(mCurrPt.getX() - mPrevPt.getX()) > MAX_MULTITOUCH_POS_JUMP_SIZE
|| Math.abs(mCurrPt.getY() - mPrevPt.getY()) > MAX_MULTITOUCH_POS_JUMP_SIZE
|| Math.abs(mCurrPt.getMultiTouchWidth() - mPrevPt.getMultiTouchWidth()) * .5f > MAX_MULTITOUCH_DIM_JUMP_SIZE
|| Math.abs(mCurrPt.getMultiTouchHeight() - mPrevPt.getMultiTouchHeight()) * .5f > MAX_MULTITOUCH_DIM_JUMP_SIZE) {
// Jumped too far, probably event noise, reset and ignore events for a bit
anchorAtThisPositionAndScale();
mSettleStartTime = mCurrPt.getEventTime();
mSettleEndTime = mSettleStartTime + EVENT_SETTLE_TIME_INTERVAL;
} else if (mCurrPt.eventTime < mSettleEndTime) {
// Events have not yet settled, reset
anchorAtThisPositionAndScale();
} else {
// Stretch to new position and size
performDragOrPinch();
}
}
break;
}
if (DEBUG)
Log.i("MultiTouch", "Got here 7 - " + mMode + " " + mCurrPt.getNumTouchPoints() + " " + mCurrPt.isDown() + mCurrPt.isMultiTouch());
}
// ------------------------------------------------------------------------------------
/** A class that packages up all MotionEvent information with all derived multitouch information (if available) */
public static class PointInfo {
// Multitouch information
private int numPoints;
private float[] xs = new float[MAX_TOUCH_POINTS];
private float[] ys = new float[MAX_TOUCH_POINTS];
private float[] pressures = new float[MAX_TOUCH_POINTS];
private int[] pointerIds = new int[MAX_TOUCH_POINTS];
// Midpoint of pinch operations
private float xMid, yMid, pressureMid;
// Width/diameter/angle of pinch operations
private float dx, dy, diameter, diameterSq, angle;
// Whether or not there is at least one finger down (isDown) and/or at least two fingers down (isMultiTouch)
private boolean isDown, isMultiTouch;
// Whether or not these fields have already been calculated, for caching purposes
private boolean diameterSqIsCalculated, diameterIsCalculated, angleIsCalculated;
// Event action code and event time
private int action;
private long eventTime;
// -------------------------------------------------------------------------------------------------------------------------------------------
/** Set all point info */
private void set(int numPoints, float[] x, float[] y, float[] pressure, int[] pointerIds, int action, boolean isDown, long eventTime) {
if (DEBUG)
Log.i("MultiTouch", "Got here 8 - " + +numPoints + " " + x[0] + " " + y[0] + " " + (numPoints > 1 ? x[1] : x[0]) + " "
+ (numPoints > 1 ? y[1] : y[0]) + " " + action + " " + isDown);
this.eventTime = eventTime;
this.action = action;
this.numPoints = numPoints;
for (int i = 0; i < numPoints; i++) {
this.xs[i] = x[i];
this.ys[i] = y[i];
this.pressures[i] = pressure[i];
this.pointerIds[i] = pointerIds[i];
}
this.isDown = isDown;
this.isMultiTouch = numPoints >= 2;
if (isMultiTouch) {
xMid = (x[0] + x[1]) * .5f;
yMid = (y[0] + y[1]) * .5f;
pressureMid = (pressure[0] + pressure[1]) * .5f;
dx = Math.abs(x[1] - x[0]);
dy = Math.abs(y[1] - y[0]);
} else {
// Single-touch event
xMid = x[0];
yMid = y[0];
pressureMid = pressure[0];
dx = dy = 0.0f;
}
// Need to re-calculate the expensive params if they're needed
diameterSqIsCalculated = diameterIsCalculated = angleIsCalculated = false;
}
/**
* Copy all fields from one PointInfo class to another. PointInfo objects are volatile so you should use this if you want to keep track of the
* last touch event in your own code.
*/
public void set(PointInfo other) {
this.numPoints = other.numPoints;
for (int i = 0; i < numPoints; i++) {
this.xs[i] = other.xs[i];
this.ys[i] = other.ys[i];
this.pressures[i] = other.pressures[i];
this.pointerIds[i] = other.pointerIds[i];
}
this.xMid = other.xMid;
this.yMid = other.yMid;
this.pressureMid = other.pressureMid;
this.dx = other.dx;
this.dy = other.dy;
this.diameter = other.diameter;
this.diameterSq = other.diameterSq;
this.angle = other.angle;
this.isDown = other.isDown;
this.action = other.action;
this.isMultiTouch = other.isMultiTouch;
this.diameterIsCalculated = other.diameterIsCalculated;
this.diameterSqIsCalculated = other.diameterSqIsCalculated;
this.angleIsCalculated = other.angleIsCalculated;
this.eventTime = other.eventTime;
}
// -------------------------------------------------------------------------------------------------------------------------------------------
/** True if number of touch points >= 2. */
public boolean isMultiTouch() {
return isMultiTouch;
}
/** Difference between x coords of touchpoint 0 and 1. */
public float getMultiTouchWidth() {
return isMultiTouch ? dx : 0.0f;
}
/** Difference between y coords of touchpoint 0 and 1. */
public float getMultiTouchHeight() {
return isMultiTouch ? dy : 0.0f;
}
/** Fast integer sqrt, by Jim Ulery. Much faster than Math.sqrt() for integers. */
private int julery_isqrt(int val) {
int temp, g = 0, b = 0x8000, bshft = 15;
do {
if (val >= (temp = (((g << 1) + b) << bshft--))) {
g += b;
val -= temp;
}
} while ((b >>= 1) > 0);
return g;
}
/** Calculate the squared diameter of the multitouch event, and cache it. Use this if you don't need to perform the sqrt. */
public float getMultiTouchDiameterSq() {
if (!diameterSqIsCalculated) {
diameterSq = (isMultiTouch ? dx * dx + dy * dy : 0.0f);
diameterSqIsCalculated = true;
}
return diameterSq;
}
/** Calculate the diameter of the multitouch event, and cache it. Uses fast int sqrt but gives accuracy to 1/16px. */
public float getMultiTouchDiameter() {
if (!diameterIsCalculated) {
if (!isMultiTouch) {
diameter = 0.0f;
} else {
// Get 1/16 pixel's worth of subpixel accuracy, works on screens up to 2048x2048
// before we get overflow (at which point you can reduce or eliminate subpix
// accuracy, or use longs in julery_isqrt())
float diamSq = getMultiTouchDiameterSq();
diameter = (diamSq == 0.0f ? 0.0f : (float) julery_isqrt((int) (256 * diamSq)) / 16.0f);
// Make sure diameter is never less than dx or dy, for trig purposes
if (diameter < dx)
diameter = dx;
if (diameter < dy)
diameter = dy;
}
diameterIsCalculated = true;
}
return diameter;
}
/**
* Calculate the angle of a multitouch event, and cache it. Actually gives the smaller of the two angles between the x axis and the line
* between the two touchpoints, so range is [0,Math.PI/2]. Uses Math.atan2().
*/
public float getMultiTouchAngle() {
if (!angleIsCalculated) {
if (!isMultiTouch)
angle = 0.0f;
else
angle = (float) Math.atan2(ys[1] - ys[0], xs[1] - xs[0]);
angleIsCalculated = true;
}
return angle;
}
// -------------------------------------------------------------------------------------------------------------------------------------------
/** Return the total number of touch points */
public int getNumTouchPoints() {
return numPoints;
}
/** Return the X coord of the first touch point if there's only one, or the midpoint between first and second touch points if two or more. */
public float getX() {
return xMid;
}
/** Return the array of X coords -- only the first getNumTouchPoints() of these is defined. */
public float[] getXs() {
return xs;
}
/** Return the X coord of the first touch point if there's only one, or the midpoint between first and second touch points if two or more. */
public float getY() {
return yMid;
}
/** Return the array of Y coords -- only the first getNumTouchPoints() of these is defined. */
public float[] getYs() {
return ys;
}
/**
* Return the array of pointer ids -- only the first getNumTouchPoints() of these is defined. These don't have to be all the numbers from 0 to
* getNumTouchPoints()-1 inclusive, numbers can be skipped if a finger is lifted and the touch sensor is capable of detecting that that
* particular touch point is no longer down. Note that a lot of sensors do not have this capability: when finger 1 is lifted up finger 2
* becomes the new finger 1. However in theory these IDs can correct for that. Convert back to indices using MotionEvent.findPointerIndex().
*/
public int[] getPointerIds() {
return pointerIds;
}
/** Return the pressure the first touch point if there's only one, or the average pressure of first and second touch points if two or more. */
public float getPressure() {
return pressureMid;
}
/** Return the array of pressures -- only the first getNumTouchPoints() of these is defined. */
public float[] getPressures() {
return pressures;
}
// -------------------------------------------------------------------------------------------------------------------------------------------
public boolean isDown() {
return isDown;
}
public int getAction() {
return action;
}
public long getEventTime() {
return eventTime;
}
}
// ------------------------------------------------------------------------------------
/**
* A class that is used to store scroll offsets and scale information for objects that are managed by the multitouch controller
*/
public static class PositionAndScale {
private float xOff, yOff, scale, scaleX, scaleY, angle;
private boolean updateScale, updateScaleXY, updateAngle;
/**
* Set position and optionally scale, anisotropic scale, and/or angle. Where if the corresponding "update" flag is set to false, the field's
* value will not be changed during a pinch operation. If the value is not being updated *and* the value is not used by the client
* application, then the value can just be zero. However if the value is not being updated but the value *is* being used by the client
* application, the value should still be specified and the update flag should be false (e.g. angle of the object being dragged should still
* be specified even if the program is in "resize" mode rather than "rotate" mode).
*/
public void set(float xOff, float yOff, boolean updateScale, float scale, boolean updateScaleXY, float scaleX, float scaleY,
boolean updateAngle, float angle) {
this.xOff = xOff;
this.yOff = yOff;
this.updateScale = updateScale;
this.scale = scale == 0.0f ? 1.0f : scale;
this.updateScaleXY = updateScaleXY;
this.scaleX = scaleX == 0.0f ? 1.0f : scaleX;
this.scaleY = scaleY == 0.0f ? 1.0f : scaleY;
this.updateAngle = updateAngle;
this.angle = angle;
}
/** Set position and optionally scale, anisotropic scale, and/or angle, without changing the "update" flags. */
protected void set(float xOff, float yOff, float scale, float scaleX, float scaleY, float angle) {
this.xOff = xOff;
this.yOff = yOff;
this.scale = scale == 0.0f ? 1.0f : scale;
this.scaleX = scaleX == 0.0f ? 1.0f : scaleX;
this.scaleY = scaleY == 0.0f ? 1.0f : scaleY;
this.angle = angle;
}
public float getXOff() {
return xOff;
}
public float getYOff() {
return yOff;
}
public float getScale() {
return !updateScale ? 1.0f : scale;
}
/** Included in case you want to support anisotropic scaling */
public float getScaleX() {
return !updateScaleXY ? 1.0f : scaleX;
}
/** Included in case you want to support anisotropic scaling */
public float getScaleY() {
return !updateScaleXY ? 1.0f : scaleY;
}
public float getAngle() {
return !updateAngle ? 0.0f : angle;
}
}
// ------------------------------------------------------------------------------------
public static interface MultiTouchObjectCanvas<T> {
/**
* See if there is a draggable object at the current point. Returns the object at the point, or null if nothing to drag. To start a multitouch
* drag/stretch operation, this routine must return some non-null reference to an object. This object is passed into the other methods in this
* interface when they are called.
*
* @param touchPoint
* The point being tested (in object coordinates). Return the topmost object under this point, or if dragging/stretching the whole
* canvas, just return a reference to the canvas.
* @return a reference to the object under the point being tested, or null to cancel the drag operation. If dragging/stretching the whole
* canvas (e.g. in a photo viewer), always return non-null, otherwise the stretch operation won't work.
*/
public T getDraggableObjectAtPoint(PointInfo touchPoint);
/**
* Get the screen coords of the dragged object's origin, and scale multiplier to convert screen coords to obj coords. The job of this routine
* is to call the .set() method on the passed PositionAndScale object to record the initial position and scale of the object (in object
* coordinates) before any dragging/stretching takes place.
*
* @param obj
* The object being dragged/stretched.
* @param objPosAndScaleOut
* Output parameter: You need to call objPosAndScaleOut.set() to record the current position and scale of obj.
*/
public void getPositionAndScale(T obj, PositionAndScale objPosAndScaleOut);
/**
* Callback to update the position and scale (in object coords) of the currently-dragged object.
*
* @param obj
* The object being dragged/stretched.
* @param newObjPosAndScale
* The new position and scale of the object, in object coordinates. Use this to move/resize the object before returning.
* @param touchPoint
* Info about the current touch point, including multitouch information and utilities to calculate and cache multitouch pinch
* diameter etc. (Note: touchPoint is volatile, if you want to keep any fields of touchPoint, you must copy them before the method
* body exits.)
* @return true if setting the position and scale of the object was successful, or false if the position or scale parameters are out of range
* for this object.
*/
public boolean setPositionAndScale(T obj, PositionAndScale newObjPosAndScale, PointInfo touchPoint);
/**
* Select an object at the given point. Can be used to bring the object to top etc. Only called when first touchpoint goes down, not when
* multitouch is initiated. Also called with null on touch-up.
*
* @param obj
* The object being selected by single-touch, or null on touch-up.
* @param touchPoint
* The current touch point.
*/
public void selectObject(T obj, PointInfo touchPoint);
}
}

View File

@ -1 +1 @@
fe4815b00d6e0564ee73979cc062a3b81ee0ae79
d09725f4302ca8fa1f0ce71afbe4ad0ab9418713

View File

@ -45,6 +45,7 @@ files
("cocos2dx/cocoa")
[cocoa]
"*.cpp"
"*.h"
("cocos2dx/effects")
[effects]

View File

@ -25,6 +25,7 @@ cocoa/CCAffineTransform.cpp \
cocoa/CCGeometry.cpp \
cocoa/CCAutoreleasePool.cpp \
cocoa/CCData.cpp \
cocoa/CCNS.cpp \
cocoa/CCObject.cpp \
cocoa/CCSet.cpp \
cocoa/CCZone.cpp \
@ -64,7 +65,6 @@ platform/CCCommon.cpp \
platform/CCParticleSystemPoint_mobile.cpp \
platform/CCTransition_mobile.cpp \
platform/platform.cpp \
platform/android/CCNS_android.cpp \
platform/android/CCEGLView_android.cpp \
platform/android/CCAccelerometer_android.cpp \
platform/android/CCApplication_android.cpp \

180
cocos2dx/cocoa/CCNS.cpp Normal file
View File

@ -0,0 +1,180 @@
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "CCNS.h"
#include <string>
#include <vector>
#include <stdlib.h>
typedef std::vector<std::string> strArray;
// string toolkit
void split(std::string src, const char* token, strArray& vect)
{
int nend=0;
int nbegin=0;
while(nend != -1)
{
nend = src.find(token, nbegin);
if(nend == -1)
vect.push_back(src.substr(nbegin, src.length()-nbegin));
else
vect.push_back(src.substr(nbegin, nend-nbegin));
nbegin = nend + strlen(token);
}
}
// first, judge whether the form of the string like this: {x,y}
// if the form is right,the string will be splited into the parameter strs;
// or the parameter strs will be empty.
// if the form is right return true,else return false.
bool splitWithForm(const char* pStr, strArray& strs)
{
bool bRet = false;
do
{
CC_BREAK_IF(!pStr);
// string is empty
std::string content = pStr;
CC_BREAK_IF(content.length() == 0);
int nPosLeft = content.find('{');
int nPosRight = content.find('}');
// don't have '{' and '}'
CC_BREAK_IF(nPosLeft == std::string::npos || nPosRight == std::string::npos);
// '}' is before '{'
CC_BREAK_IF(nPosLeft > nPosRight);
std::string pointStr = content.substr(nPosLeft + 1, nPosRight - nPosLeft - 1);
// nothing between '{' and '}'
CC_BREAK_IF(pointStr.length() == 0);
int nPos1 = pointStr.find('{');
int nPos2 = pointStr.find('}');
// contain '{' or '}'
CC_BREAK_IF(nPos1 != std::string::npos || nPos2 != std::string::npos);
split(pointStr, ",", strs);
if (strs.size() != 2 || strs[0].length() == 0 || strs[1].length() == 0)
{
strs.clear();
break;
}
bRet = true;
} while (0);
return bRet;
}
// implement the functions
namespace cocos2d
{
CCRect CCRectFromString(const char* pszContent)
{
CCRect result = CCRectZero;
do
{
CC_BREAK_IF(!pszContent);
std::string content = pszContent;
// find the first '{' and the third '}'
int nPosLeft = content.find('{');
int nPosRight = content.find('}');
for (int i = 1; i < 3; ++i)
{
if (nPosRight == std::string::npos)
{
break;
}
nPosRight = content.find('}', nPosRight + 1);
}
CC_BREAK_IF(nPosLeft == std::string::npos || nPosRight == std::string::npos);
content = content.substr(nPosLeft + 1, nPosRight - nPosLeft - 1);
int nPointEnd = content.find('}');
CC_BREAK_IF(nPointEnd == std::string::npos);
nPointEnd = content.find(',', nPointEnd);
CC_BREAK_IF(nPointEnd == std::string::npos);
// get the point string and size string
std::string pointStr = content.substr(0, nPointEnd);
std::string sizeStr = content.substr(nPointEnd + 1, content.length() - nPointEnd);
// split the string with ','
strArray pointInfo;
CC_BREAK_IF(!splitWithForm(pointStr.c_str(), pointInfo));
strArray sizeInfo;
CC_BREAK_IF(!splitWithForm(sizeStr.c_str(), sizeInfo));
float x = (float) atof(pointInfo[0].c_str());
float y = (float) atof(pointInfo[1].c_str());
float width = (float) atof(sizeInfo[0].c_str());
float height = (float) atof(sizeInfo[1].c_str());
result = CCRectMake(x, y, width, height);
} while (0);
return result;
}
CCPoint CCPointFromString(const char* pszContent)
{
CCPoint ret = CCPointZero;
do
{
strArray strs;
CC_BREAK_IF(!splitWithForm(pszContent, strs));
float x = (float) atof(strs[0].c_str());
float y = (float) atof(strs[1].c_str());
ret = CCPointMake(x, y);
} while (0);
return ret;
}
CCSize CCSizeFromString(const char* pszContent)
{
CCSize ret = CCSizeZero;
do
{
strArray strs;
CC_BREAK_IF(!splitWithForm(pszContent, strs));
float width = (float) atof(strs[0].c_str());
float height = (float) atof(strs[1].c_str());
ret = CCSizeMake(width, height);
} while (0);
return ret;
}
}

71
cocos2dx/cocoa/CCNS.h Normal file
View File

@ -0,0 +1,71 @@
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __PLATFOMR_CCNS_H__
#define __PLATFOMR_CCNS_H__
#include "CCGeometry.h"
namespace cocos2d
{
/**
@brief Returns a Core Graphics rectangle structure corresponding to the data in a given string.
@param pszContent A string object whose contents are of the form "{{x,y},{w, h}}",
where x is the x coordinate, y is the y coordinate, w is the width, and h is the height.
These components can represent integer or float values.
An example of a valid string is "{{3,2},{4,5}}".
The string is not localized, so items are always separated with a comma.
@return A Core Graphics structure that represents a rectangle.
If the string is not well-formed, the function returns CCRectZero.
*/
CCRect CCRectFromString(const char* pszContent);
/**
@brief Returns a Core Graphics point structure corresponding to the data in a given string.
@param pszContent A string object whose contents are of the form "{x,y}",
where x is the x coordinate and y is the y coordinate.
The x and y values can represent integer or float values.
An example of a valid string is "{3.0,2.5}".
The string is not localized, so items are always separated with a comma.
@return A Core Graphics structure that represents a point.
If the string is not well-formed, the function returns CCPointZero.
*/
CCPoint CCPointFromString(const char* pszContent);
/**
@brief Returns a Core Graphics size structure corresponding to the data in a given string.
@param pszContent A string object whose contents are of the form "{w, h}",
where w is the width and h is the height.
The w and h values can be integer or float values.
An example of a valid string is "{3.0,2.5}".
The string is not localized, so items are always separated with a comma.
@return A Core Graphics structure that represents a size.
If the string is not well-formed, the function returns CCSizeZero.
*/
CCSize CCSizeFromString(const char* pszContent);
}
#endif // __PLATFOMR_CCNS_H__

View File

@ -136,7 +136,7 @@ private:
protected:
CCDictionary<std::string, CCSpriteFrame*> *m_pSpriteFrames;
CCDictionary<std::string, CCSpriteFrame*> *m_pSpriteFramesAliases;
CCDictionary<std::string, CCString*> *m_pSpriteFramesAliases;
};
}//namespace cocos2d

View File

@ -23,7 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "platform/CCNS.h"
#include "cocoa/CCNS.h"
#include "CCDirector.h"
#include "CCScene.h"
#include "CCMutableArray.h"

View File

@ -24,7 +24,7 @@ THE SOFTWARE.
#include "CCFileUtils.h"
#if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS && CC_TARGET_PLATFORM != CC_PLATFORM_AIRPLAY)
#if (CC_TARGET_PLATFORM != CC_PLATFORM_IOS) && (CC_TARGET_PLATFORM != CC_PLATFORM_AIRPLAY)
#include <stack>
#include <libxml/parser.h>
@ -55,12 +55,18 @@ public:
std::stack<CCDictionary<std::string, CCObject*>*> m_tDictStack;
std::string m_sCurKey;///< parsed key
CCSAXState m_tState;
bool m_bInArray;
CCMutableArray<CCObject*> *m_pArray;
public:
CCDictMaker()
{
m_pRootDict = NULL;
m_pCurDict = NULL;
m_tState = SAX_NONE;
m_pArray = NULL;
m_bInArray = false;
}
~CCDictMaker()
{
@ -119,6 +125,11 @@ public:
}
else
{
if (sName == "array")
{
m_bInArray = true;
m_pArray = new CCMutableArray<CCObject*>();
}
m_tState = SAX_NONE;
}
}
@ -134,6 +145,14 @@ public:
m_pCurDict = (CCDictionary<std::string, CCObject*>*)(m_tDictStack.top());
}
}
else if (sName == "array")
{
CCAssert(m_bInArray, "The plist file is wrong!");
m_pCurDict->setObject(m_pArray, m_sCurKey);
m_pArray->release();
m_pArray = NULL;
m_bInArray = false;
}
m_tState = SAX_NONE;
}
@ -156,7 +175,15 @@ public:
case SAX_STRING:
{
CCAssert(!m_sCurKey.empty(), "not found key : <integet/real>");
m_pCurDict->setObject(pText, m_sCurKey);
if (m_bInArray)
{
m_pArray->addObject(pText);
}
else
{
m_pCurDict->setObject(pText, m_sCurKey);
}
break;
}
}

View File

@ -1,39 +0,0 @@
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#ifndef __PLATFOMR_CCNS_H__
#define __PLATFOMR_CCNS_H__
#include "CCGeometry.h"
namespace cocos2d
{
CCRect CCRectFromString(const char* pszContent);
CCPoint CCPointFromString(const char* pszContent);
CCSize CCSizeFromString(const char* pszContent);
}
#endif // __PLATFOMR_CCNS_H__

View File

@ -53,6 +53,8 @@ public:
std::stack<CCDictionary<std::string, CCObject*>*> m_tDictStack;
std::string m_sCurKey;///< parsed key
CCSAXState m_tState;
bool m_bInArray;
CCMutableArray<CCObject*> *m_pArray;
public:
CCDictMaker()
@ -60,6 +62,9 @@ public:
m_pRootDict = NULL;
m_pCurDict = NULL;
m_tState = SAX_NONE;
m_pArray = NULL;
m_bInArray = false;
}
~CCDictMaker()
{
@ -80,91 +85,115 @@ public:
void startElement(void *ctx, const XML_Char *name, const XML_Char **atts)
{
CCDictMaker *pMaker = this;
std::string sName((char*)name);
if( sName == "dict" )
{
CCDictionary<std::string, CCObject*> *pNewDict = new CCDictionary<std::string, CCObject*>();
if(! pMaker->m_pRootDict)
if(! m_pRootDict)
{
pMaker->m_pRootDict = pNewDict;
m_pRootDict = pNewDict;
pNewDict->autorelease();
}
else
{
CCAssert(pMaker->m_pCurDict && !pMaker->m_sCurKey.empty(), "");
pMaker->m_pCurDict->setObject(pNewDict, pMaker->m_sCurKey);
CCAssert(m_pCurDict && !m_sCurKey.empty(), "");
m_pCurDict->setObject(pNewDict, m_sCurKey);
pNewDict->release();
pMaker->m_sCurKey.clear();
m_sCurKey.clear();
}
pMaker->m_pCurDict = pNewDict;
pMaker->m_tDictStack.push(pMaker->m_pCurDict);
pMaker->m_tState = SAX_DICT;
m_pCurDict = pNewDict;
m_tDictStack.push(m_pCurDict);
m_tState = SAX_DICT;
}
else if(sName == "key")
{
pMaker->m_tState = SAX_KEY;
m_tState = SAX_KEY;
}
else if(sName == "integer")
{
pMaker->m_tState = SAX_INT;
m_tState = SAX_INT;
}
else if(sName == "real")
{
pMaker->m_tState = SAX_REAL;
m_tState = SAX_REAL;
}
else if(sName == "string")
{
pMaker->m_tState = SAX_STRING;
m_tState = SAX_STRING;
}
else
{
pMaker->m_tState = SAX_NONE;
if (sName == "array")
{
m_bInArray = true;
m_pArray = new CCMutableArray<CCObject*>();
}
m_tState = SAX_NONE;
}
}
void endElement(void *ctx, const XML_Char *name)
{
CCDictMaker * pMaker = this;
std::string sName((char*)name);
if( sName == "dict" )
{
pMaker->m_tDictStack.pop();
if ( !pMaker->m_tDictStack.empty() )
m_tDictStack.pop();
if ( !m_tDictStack.empty() )
{
pMaker->m_pCurDict = (CCDictionary<std::string, CCObject*>*)(pMaker->m_tDictStack.top());
m_pCurDict = (CCDictionary<std::string, CCObject*>*)(m_tDictStack.top());
}
}
pMaker->m_tState = SAX_NONE;
else if (sName == "array")
{
CCAssert(m_bInArray, "The plist file is wrong!");
m_pCurDict->setObject(m_pArray, m_sCurKey);
m_pArray->release();
m_pArray = NULL;
m_bInArray = false;
}
m_tState = SAX_NONE;
}
void textHandler(void *ctx, const XML_Char *ch, int len)
{
CCDictMaker * pMaker = this;
if (pMaker->m_tState == SAX_NONE)
if (m_tState == SAX_NONE)
{
return;
}
CCString *pText = new CCString();
pText->m_sString = std::string((char*)ch,0,len);
switch(pMaker->m_tState)
switch(m_tState)
{
case SAX_KEY:
{
pMaker->m_sCurKey = pText->m_sString;
m_sCurKey = pText->m_sString;
}
break;
case SAX_INT:
case SAX_REAL:
{
CCAssert(!pMaker->m_sCurKey.empty(), "not found real : <integet/real>");
pMaker->m_pCurDict->setObject(pText, pMaker->m_sCurKey);
CCAssert(!m_sCurKey.empty(), "not found real : <integet/real>");
if (m_bInArray)
{
m_pArray->addObject(pText);
}
else
{
m_pCurDict->setObject(pText, m_sCurKey);
}
break;
}
case SAX_STRING:
{
CCAssert(!pMaker->m_sCurKey.empty(), "not found string");
pMaker->m_pCurDict->setObject(pText, pMaker->m_sCurKey);
CCAssert(!m_sCurKey.empty(), "not found string");
if (m_bInArray)
{
m_pArray->addObject(pText);
}
else
{
m_pCurDict->setObject(pText, m_sCurKey);
}
break;
}
}

View File

@ -1,42 +0,0 @@
/****************************************************************************
Copyright (c) 2011 cocos2d-x.org http://cocos2d-x.org
Copyright (c) 2011 Максим Аксенов
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "platform/CCNS.h"
///@todo implement the functions
NS_CC_BEGIN;
CCRect CCRectFromString(const char* pszContent)
{
return CCRectZero;
}
CCPoint CCPointFromString(const char* pszContent)
{
return CCPointZero;
}
CCSize CCSizeFromString(const char* pszContent)
{
return CCSizeZero;
}
NS_CC_END;

View File

@ -1,43 +0,0 @@
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "platform/CCNS.h"
///@todo implement the functions
namespace cocos2d
{
CCRect CCRectFromString(const char* pszContent)
{
return CCRectZero;
}
CCPoint CCPointFromString(const char* pszContent)
{
return CCPointZero;
}
CCSize CCSizeFromString(const char* pszContent)
{
return CCSizeZero;
}
}

View File

@ -30,11 +30,13 @@ THE SOFTWARE.
#include "CCGeometry.h"
#include "platform/android/CCAccelerometer_android.h"
#include <android/log.h>
#define LOG_TAG "Cocos2dJni"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#if 0
#define LOG_TAG "Cocos2dJni"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#else
#define LOGD(...)
#endif
using namespace cocos2d;
@ -42,8 +44,7 @@ extern "C"
{
#define MAX_TOUCHES 5
static cocos2d::CCTouch *s_pTouches[MAX_TOUCHES] = { NULL };
static cocos2d::CCSet s_set;
static CCTouch *s_pTouches[MAX_TOUCHES] = { NULL };
// handle accelerometer changes
@ -58,84 +59,54 @@ extern "C"
timeStamp);
}
// handle touch event
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesBegin(JNIEnv* env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys)
// handle touch event
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesBegin(JNIEnv* env, jobject thiz, jint id, jfloat x, jfloat y)
{
int size = env->GetArrayLength(ids);
jint id[size];
jfloat x[size];
jfloat y[size];
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
CCSet set;
env->GetIntArrayRegion(ids, 0, size, id);
env->GetFloatArrayRegion(xs, 0, size, x);
env->GetFloatArrayRegion(ys, 0, size, y);
CCTouch *pTouch = s_pTouches[id];
if (! pTouch)
{
LOGD("Beginning touches with id: %d, x=%f, y=%f", id, x, y);
for( int i = 0 ; i < size ; i++ ) {
cocos2d::CCTouch* pTouch = s_pTouches[id[i]];
LOGD("Should create new pTouch if null: %d", pTouch);
if (!pTouch)
{
pTouch = new cocos2d::CCTouch;
}
pTouch = new CCTouch();
pTouch->SetTouchInfo(0, (x - rcRect.origin.x) / fScreenScaleFactor, (y - rcRect.origin.y) / fScreenScaleFactor);
s_pTouches[id] = pTouch;
set.addObject(pTouch);
LOGD("Beginning touches with id: %d, x=%f, y=%f", id[i], x[i], y[i]);
pTouch->SetTouchInfo(0, (x[i] - rcRect.origin.x) / fScreenScaleFactor ,
(y[i] - rcRect.origin.y) / fScreenScaleFactor);
s_set.addObject(pTouch);
s_pTouches[id[i]] = pTouch;
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->getDelegate()->touchesBegan(&set, NULL);
}
else
{
LOGD("Beginnig touches with id: %d error", id);
}
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->getDelegate()->touchesBegan(&s_set, NULL);
}
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesEnd(JNIEnv* env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys)
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesEnd(JNIEnv* env, jobject thiz, jint id, jfloat x, jfloat y)
{
int size = env->GetArrayLength(ids);
jint id[size];
jfloat x[size];
jfloat y[size];
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
env->GetIntArrayRegion(ids, 0, size, id);
env->GetFloatArrayRegion(xs, 0, size, x);
env->GetFloatArrayRegion(ys, 0, size, y);
CCSet set;
/* Add to the set to send to the director */
for( int i = 0 ; i < size ; i++ ) {
cocos2d::CCTouch* pTouch = s_pTouches[id[i]];
LOGD("Ending touches with id: %d, x=%f, y=%f", id[i], x[i], y[i]);
if (pTouch)
{
pTouch->SetTouchInfo(0, (x[i] - rcRect.origin.x) / fScreenScaleFactor ,
(y[i] - rcRect.origin.y) / fScreenScaleFactor);
s_set.addObject(pTouch);
} else {
LOGD("Error adding the touch to remove");
}
}
CCTouch* pTouch = s_pTouches[id];
if (pTouch)
{
LOGD("Ending touches with id: %d, x=%f, y=%f", id, x, y);
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->getDelegate()->touchesEnded(&s_set, NULL);
pTouch->SetTouchInfo(0, (x - rcRect.origin.x) / fScreenScaleFactor , (y - rcRect.origin.y) / fScreenScaleFactor);
set.addObject(pTouch);
/* Update the set status */
for( int i = 0 ; i < size ; i++ ) {
cocos2d::CCTouch* pTouch = s_pTouches[id[i]];
LOGD("Ending touches with id: %d, x=%f, y=%f", id[i], x[i], y[i]);
if (pTouch)
{
s_set.removeObject(pTouch);
pTouch->release();
s_pTouches[id[i]] = NULL;
} else {
LOGD("Error removing from the set!");
}
// release the object
pTouch->release();
s_pTouches[id] = NULL;
}
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->getDelegate()->touchesEnded(&set, NULL);
} else {
LOGD("Ending touches with id: %d error", id);
}
}
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesMove(JNIEnv* env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys)
@ -146,6 +117,7 @@ extern "C"
jfloat y[size];
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
CCSet set;
env->GetIntArrayRegion(ids, 0, size, id);
env->GetFloatArrayRegion(xs, 0, size, x);
@ -158,11 +130,17 @@ extern "C"
{
pTouch->SetTouchInfo(0, (x[i] - rcRect.origin.x) / fScreenScaleFactor ,
(y[i] - rcRect.origin.y) / fScreenScaleFactor);
s_set.addObject(pTouch);
set.addObject(pTouch);
}
else
{
// It is error, should return.
LOGD("Moving touches with id: %d error", id[i]);
return;
}
}
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->getDelegate()->touchesMoved(&s_set, NULL);
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->getDelegate()->touchesMoved(&set, NULL);
}
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesCancel(JNIEnv* env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys)
@ -173,6 +151,7 @@ extern "C"
jfloat y[size];
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
CCSet set;
env->GetIntArrayRegion(ids, 0, size, id);
env->GetFloatArrayRegion(xs, 0, size, x);
@ -184,12 +163,13 @@ extern "C"
{
pTouch->SetTouchInfo(0, (x[i] - rcRect.origin.x) / fScreenScaleFactor ,
(y[i] - rcRect.origin.y) / fScreenScaleFactor);
s_set.addObject(pTouch);
set.addObject(pTouch);
s_pTouches[id[i]] = NULL;
pTouch->release();
}
}
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->getDelegate()->touchesCancelled(&s_set, NULL);
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->getDelegate()->touchesCancelled(&set, NULL);
}
void Java_org_cocos2dx_lib_Cocos2dxActivity_nativeSetPaths(JNIEnv* env, jobject thiz, jstring apkPath)

View File

@ -115,155 +115,208 @@ static const char* static_fullPathFromRelativePath(const char *pszRelativePath)
// do not convert an absolute path (starting with '/')
NSString *relPath = [NSString stringWithUTF8String: pszRelativePath];
NSString *fullpath = nil;
// only if it is not an absolute path
if( ! [relPath isAbsolutePath] )
{
NSString *file = [relPath lastPathComponent];
NSString *imageDirectory = [relPath stringByDeletingLastPathComponent];
fullpath = [[NSBundle mainBundle] pathForResource:file
ofType:nil
inDirectory:imageDirectory];
}
if (fullpath == nil)
fullpath = relPath;
fullpath = getDoubleResolutionImage(fullpath);
return [fullpath UTF8String];
// only if it is not an absolute path
if( ! [relPath isAbsolutePath] )
{
NSString *file = [relPath lastPathComponent];
NSString *imageDirectory = [relPath stringByDeletingLastPathComponent];
fullpath = [[NSBundle mainBundle] pathForResource:file
ofType:nil
inDirectory:imageDirectory];
}
if (fullpath == nil)
fullpath = relPath;
fullpath = getDoubleResolutionImage(fullpath);
return [fullpath UTF8String];
}
namespace cocos2d {
typedef enum
typedef enum
{
SAX_NONE = 0,
SAX_KEY,
SAX_DICT,
SAX_INT,
SAX_REAL,
SAX_STRING
}CCSAXState;
class CCDictMaker : public CCSAXDelegator
{
public:
CCDictionary<std::string, CCObject*> *m_pRootDict;
CCDictionary<std::string, CCObject*> *m_pCurDict;
std::stack<CCDictionary<std::string, CCObject*>*> m_tDictStack;
std::string m_sCurKey;///< parsed key
CCSAXState m_tState;
bool m_bInArray;
CCMutableArray<CCObject*> *m_pArray;
public:
CCDictMaker()
{
SAX_NONE = 0,
SAX_KEY,
SAX_DICT,
SAX_INT,
SAX_REAL,
SAX_STRING
}CCSAXState;
m_pRootDict = NULL;
m_pCurDict = NULL;
m_tState = SAX_NONE;
class CCDictMaker : public CCSAXDelegator
m_pArray = NULL;
m_bInArray = false;
}
~CCDictMaker()
{
public:
CCDictionary<std::string, CCObject*> *m_pRootDict;
CCDictionary<std::string, CCObject*> *m_pCurDict;
std::stack<CCDictionary<std::string, CCObject*>*> m_tDictStack;
std::string m_sCurKey;///< parsed key
CCSAXState m_tState;
public:
CCDictMaker()
{
m_pRootDict = NULL;
m_pCurDict = NULL;
m_tState = SAX_NONE;
}
~CCDictMaker()
{
}
CCDictionary<std::string, CCObject*> *dictionaryWithContentsOfFile(const char *pFileName)
{
CCSAXParser parser;
}
CCDictionary<std::string, CCObject*> *dictionaryWithContentsOfFile(const char *pFileName)
{
CCSAXParser parser;
if (false == parser.init("UTF-8"))
{
return NULL;
}
parser.setDelegator(this);
parser.parse(pFileName);
return m_pRootDict;
}
void startElement(void *ctx, const char *name, const char **atts)
if (false == parser.init("UTF-8"))
{
std::string sName((char*)name);
if( sName == "dict" )
return NULL;
}
parser.setDelegator(this);
parser.parse(pFileName);
return m_pRootDict;
}
void startElement(void *ctx, const char *name, const char **atts)
{
std::string sName((char*)name);
if( sName == "dict" )
{
CCDictionary<std::string, CCObject*> *pNewDict = new CCDictionary<std::string, CCObject*>();
if(! m_pRootDict)
{
CCDictionary<std::string, CCObject*> *pNewDict = new CCDictionary<std::string, CCObject*>();
if(! m_pRootDict)
{
m_pRootDict = pNewDict;
pNewDict->autorelease();
}
else
{
CCAssert(m_pCurDict && !m_sCurKey.empty(), "");
m_pCurDict->setObject(pNewDict, m_sCurKey);
pNewDict->release();
m_sCurKey.clear();
}
m_pCurDict = pNewDict;
m_tDictStack.push(m_pCurDict);
m_tState = SAX_DICT;
}
else if(sName == "key")
{
m_tState = SAX_KEY;
}
else if(sName == "integer")
{
m_tState = SAX_INT;
}
else if(sName == "real")
{
m_tState = SAX_REAL;
}
else if(sName == "string")
{
m_tState = SAX_STRING;
m_pRootDict = pNewDict;
pNewDict->autorelease();
}
else
{
m_tState = SAX_NONE;
CCAssert(m_pCurDict && !m_sCurKey.empty(), "");
m_pCurDict->setObject(pNewDict, m_sCurKey);
pNewDict->release();
m_sCurKey.clear();
}
m_pCurDict = pNewDict;
m_tDictStack.push(m_pCurDict);
m_tState = SAX_DICT;
}
void endElement(void *ctx, const char *name)
else if(sName == "key")
{
std::string sName((char*)name);
if( sName == "dict" )
m_tState = SAX_KEY;
}
else if(sName == "integer")
{
m_tState = SAX_INT;
}
else if(sName == "real")
{
m_tState = SAX_REAL;
}
else if(sName == "string")
{
m_tState = SAX_STRING;
}
else
{
if (sName == "array")
{
m_tDictStack.pop();
if ( !m_tDictStack.empty() )
{
m_pCurDict = (CCDictionary<std::string, CCObject*>*)(m_tDictStack.top());
}
m_bInArray = true;
m_pArray = new CCMutableArray<CCObject*>();
}
m_tState = SAX_NONE;
}
}
void textHandler(void *ctx, const char *ch, int len)
void endElement(void *ctx, const char *name)
{
std::string sName((char*)name);
if( sName == "dict" )
{
if (m_tState == SAX_NONE)
m_tDictStack.pop();
if ( !m_tDictStack.empty() )
{
return;
m_pCurDict = (CCDictionary<std::string, CCObject*>*)(m_tDictStack.top());
}
CCString *pText = new CCString();
pText->m_sString = std::string((char*)ch,0,len);
switch(m_tState)
{
case SAX_KEY:
m_sCurKey = pText->m_sString;
break;
case SAX_INT:
case SAX_REAL:
case SAX_STRING:
{
CCAssert(!m_sCurKey.empty(), "not found key : <integet/real>");
m_pCurDict->setObject(pText, m_sCurKey);
break;
}
}
pText->release();
}
};
else if (sName == "array")
{
CCAssert(m_bInArray, "The plist file is wrong!");
m_pCurDict->setObject(m_pArray, m_sCurKey);
m_pArray->release();
m_pArray = NULL;
m_bInArray = false;
}
else if (sName == "true")
{
CCString *str = new CCString("1");
if (m_bInArray)
{
m_pArray->addObject(str);
}
else
{
m_pCurDict->setObject(str, m_sCurKey);
}
str->release();
}
else if (sName == "false")
{
CCString *str = new CCString("0");
if (m_bInArray)
{
m_pArray->addObject(str);
}
else
{
m_pCurDict->setObject(str, m_sCurKey);
}
str->release();
}
m_tState = SAX_NONE;
}
void textHandler(void *ctx, const char *ch, int len)
{
if (m_tState == SAX_NONE)
{
return;
}
CCString *pText = new CCString();
pText->m_sString = std::string((char*)ch,0,len);
switch(m_tState)
{
case SAX_KEY:
m_sCurKey = pText->m_sString;
break;
case SAX_INT:
case SAX_REAL:
case SAX_STRING:
{
CCAssert(!m_sCurKey.empty(), "not found key : <integet/real>");
if (m_bInArray)
{
m_pArray->addObject(pText);
}
else
{
m_pCurDict->setObject(pText, m_sCurKey);
}
break;
}
}
pText->release();
}
};
// record the resource path
static char s_pszResourcePath[MAX_PATH] = {0};

View File

@ -1,71 +0,0 @@
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#import <Availability.h>
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#include "platform/CCNS.h"
static cocos2d::CCRect static_CCRectFromString(const char* pszContent)
{
CGRect rect = CGRectFromString([NSString stringWithUTF8String: pszContent]);
cocos2d::CCRect ret(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
return ret;
}
static cocos2d::CCPoint static_CCPointFromString(const char* pszContent)
{
CGPoint point = CGPointFromString([NSString stringWithUTF8String: pszContent]);
cocos2d::CCPoint ret(point.x, point.y);
return ret;
}
static cocos2d::CCSize static_CCSizeFromString(const char* pszContent)
{
CGSize size = CGSizeFromString([NSString stringWithUTF8String: pszContent]);
cocos2d::CCSize ret(size.width, size.height);
return ret;
}
///@todo implement the functions
namespace cocos2d
{
CCRect CCRectFromString(const char* pszContent)
{
return static_CCRectFromString(pszContent);
}
CCPoint CCPointFromString(const char* pszContent)
{
return static_CCPointFromString(pszContent);
}
CCSize CCSizeFromString(const char* pszContent)
{
return static_CCSizeFromString(pszContent);
}
}

View File

@ -1,43 +0,0 @@
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "platform/CCNS.h"
///@todo implement the functions
namespace cocos2d
{
CCRect CCRectFromString(const char* pszContent)
{
return CCRectZero;
}
CCPoint CCPointFromString(const char* pszContent)
{
return CCPointZero;
}
CCSize CCSizeFromString(const char* pszContent)
{
return CCSizeZero;
}
}

View File

@ -1,43 +0,0 @@
/****************************************************************************
Copyright (c) 2010 cocos2d-x.org
http://www.cocos2d-x.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "platform/CCNS.h"
///@todo implement the functions
namespace cocos2d
{
CCRect CCRectFromString(const char* pszContent)
{
return CCRectZero;
}
CCPoint CCPointFromString(const char* pszContent)
{
return CCPointZero;
}
CCSize CCSizeFromString(const char* pszContent)
{
return CCSizeZero;
}
}

View File

@ -211,6 +211,14 @@
RelativePath="..\cocoa\CCGeometry.cpp"
>
</File>
<File
RelativePath="..\cocoa\CCNS.cpp"
>
</File>
<File
RelativePath="..\cocoa\CCNS.h"
>
</File>
<File
RelativePath="..\cocoa\CCObject.cpp"
>
@ -775,10 +783,6 @@
RelativePath="..\platform\CCNode_mobile.cpp"
>
</File>
<File
RelativePath="..\platform\CCNS.h"
>
</File>
<File
RelativePath="..\platform\CCParticleSystemPoint_mobile.cpp"
>
@ -858,10 +862,6 @@
RelativePath="..\platform\win32\CCEGLView_win32.h"
>
</File>
<File
RelativePath="..\platform\win32\CCNS_win32.cpp"
>
</File>
</Filter>
</Filter>
<Filter

View File

@ -53,6 +53,7 @@ OBJECTS = \
$(OBJECTS_DIR)/CCAutoreleasePool.o \
$(OBJECTS_DIR)/CCData.o \
$(OBJECTS_DIR)/CCGeometry.o \
$(OBJECTS_DIR)/CCNS.o \
$(OBJECTS_DIR)/CCObject.o \
$(OBJECTS_DIR)/CCSet.o \
$(OBJECTS_DIR)/CCZone.o \
@ -95,7 +96,6 @@ OBJECTS = \
$(OBJECTS_DIR)/CCAccelerometer_wophone.o \
$(OBJECTS_DIR)/CCApplication_wophone.o \
$(OBJECTS_DIR)/CCEGLView_wophone.o \
$(OBJECTS_DIR)/CCNS_wophone.o \
$(OBJECTS_DIR)/CCAnimation.o \
$(OBJECTS_DIR)/CCAnimationCache.o \
$(OBJECTS_DIR)/CCSprite.o \
@ -204,6 +204,9 @@ $(OBJECTS_DIR)/CCData.o : ../cocoa/CCData.cpp
$(OBJECTS_DIR)/CCGeometry.o : ../cocoa/CCGeometry.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCGeometry.o ../cocoa/CCGeometry.cpp
$(OBJECTS_DIR)/CCNS.o : ../cocoa/CCNS.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCNS.o ../cocoa/CCNS.cpp
$(OBJECTS_DIR)/CCObject.o : ../cocoa/CCObject.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCObject.o ../cocoa/CCObject.cpp
@ -330,9 +333,6 @@ $(OBJECTS_DIR)/CCApplication_wophone.o : ../platform/wophone/CCApplication_wopho
$(OBJECTS_DIR)/CCEGLView_wophone.o : ../platform/wophone/CCEGLView_wophone.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCEGLView_wophone.o ../platform/wophone/CCEGLView_wophone.cpp
$(OBJECTS_DIR)/CCNS_wophone.o : ../platform/wophone/CCNS_wophone.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCNS_wophone.o ../platform/wophone/CCNS_wophone.cpp
$(OBJECTS_DIR)/CCAnimation.o : ../sprite_nodes/CCAnimation.cpp
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCAnimation.o ../sprite_nodes/CCAnimation.cpp

View File

@ -880,6 +880,14 @@
RelativePath="..\cocoa\CCGeometry.cpp"
>
</File>
<File
RelativePath="..\cocoa\CCNS.cpp"
>
</File>
<File
RelativePath="..\cocoa\CCNS.h"
>
</File>
<File
RelativePath="..\cocoa\CCObject.cpp"
>
@ -968,10 +976,6 @@
RelativePath="..\platform\CCNode_mobile.cpp"
>
</File>
<File
RelativePath="..\platform\CCNS.h"
>
</File>
<File
RelativePath="..\platform\CCParticleSystemPoint_mobile.h"
>
@ -1051,10 +1055,6 @@
RelativePath="..\platform\wophone\CCEGLView_wophone.h"
>
</File>
<File
RelativePath="..\platform\wophone\CCNS_wophone.cpp"
>
</File>
<File
RelativePath="..\platform\wophone\NewDeleteOp.cpp"
>

View File

@ -25,7 +25,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
****************************************************************************/
#include "platform/CCNS.h"
#include "cocoa/CCNS.h"
#include "ccMacros.h"
#include "CCTextureCache.h"
#include "CCSpriteFrameCache.h"
@ -58,7 +58,7 @@ void CCSpriteFrameCache::purgeSharedSpriteFrameCache(void)
bool CCSpriteFrameCache::init(void)
{
m_pSpriteFrames= new CCDictionary<std::string, CCSpriteFrame*>();
m_pSpriteFramesAliases = new CCDictionary<std::string, CCSpriteFrame*>();
m_pSpriteFramesAliases = new CCDictionary<std::string, CCString*>();
return true;
}
@ -155,10 +155,6 @@ void CCSpriteFrameCache::addSpriteFramesWithDictionary(CCDictionary<std::string,
} else
if (format == 3)
{
/// @todo what's the format look like?
assert(false);
return;
/*
// get values
CCSize spriteSize = CCSizeFromString(valueForKey("spriteSize", frameDict));
CCPoint spriteOffset = CCPointFromString(valueForKey("spriteOffset", frameDict));
@ -167,19 +163,28 @@ void CCSpriteFrameCache::addSpriteFramesWithDictionary(CCDictionary<std::string,
bool textureRotated = atoi(valueForKey("textureRotated", frameDict)) == 0;
// get aliases
CCMutableArray<CCString*> *aliases = CCMutableArray<CCString*>dictionary->objectForKey(std::string("aliases"));
CCMutableArray<CCString*> *aliases = (CCMutableArray<CCString*> *) (frameDict->objectForKey(std::string("aliases")));
CCMutableArray<CCString*>::CCMutableArrayIterator iter;
while( alias = (CCDictionary<std::string, CCObject*>*)aliases->next(&key) )
{
std::string value = ((CCString*)alias->objectForKey(key))->m_sString();
if (m_pSpriteFramesAliases->objectForKey(value))
{
CCLOG("cocos2d: WARNING: an alias with name %s already exists", value.c_str());
}
CCString * frameKey = new CCString(key.c_str());
for (iter = aliases->begin(); iter != aliases->end(); iter++)
{
std::string oneAlias = ((CCString*) (*iter))->m_sString;
if (m_pSpriteFramesAliases->objectForKey(oneAlias))
{
CCLOG("cocos2d: WARNING: an alias with name %s already exists", oneAlias.c_str());
}
m_pSpriteFramesAliases->setObject(frameDict, value);
}
*/
m_pSpriteFramesAliases->setObject(frameKey, oneAlias);
}
frameKey->release();
// create frame
spriteFrame = new CCSpriteFrame();
spriteFrame->initWithTexture(pobTexture,
CCRectMake(textureRect.origin.x, textureRect.origin.y, spriteSize.width, spriteSize.height),
textureRotated,
spriteOffset,
spriteSourceSize);
}
// add sprite frame

View File

@ -1 +1 @@
130df27ea38ccc20118cc71eeebcccba4db470a4
f02925523f965e430f8e881c5244ee080899fb99

View File

@ -1 +1 @@
8c07d2ef5449fd386fca2f52f4347112006db602
96413c22c2a8542a63d1887b42fb9ec2ab1b15d3

View File

@ -1 +1 @@
2b6d1b09f7d781bb57632c801d23aec310bfe676
3a2dfc8ad67562d58622125a30fa53a55c717e23

View File

@ -8,4 +8,4 @@
# project structure.
# Project target.
target=android-8
target=android-7

View File

@ -1,3 +1,5 @@
# it is needed for ndk-r5
APP_STL := stlport_static
APP_ABI := armeabi armeabi-v7a
APP_MODULES := cocos2d cocosdenshion chipmunk box2d tests

View File

@ -1,119 +1,139 @@
package org.cocos2dx.lib;
import org.cocos2dx.lib.touch.metalev.multitouch.controller.MultiTouchController;
import org.cocos2dx.lib.touch.metalev.multitouch.controller.MultiTouchController.MultiTouchObjectCanvas;
import org.cocos2dx.lib.touch.metalev.multitouch.controller.MultiTouchController.PointInfo;
import org.cocos2dx.lib.touch.metalev.multitouch.controller.MultiTouchController.PositionAndScale;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.util.Log;
import android.view.MotionEvent;
public class Cocos2dxGLSurfaceView extends GLSurfaceView implements
MultiTouchObjectCanvas {
public class Cocos2dxGLSurfaceView extends GLSurfaceView{
private static final String TAG = Cocos2dxGLSurfaceView.class
.getCanonicalName();
private MultiTouchController<Void> mTouchController;
private Cocos2dxRenderer mRenderer;
private final boolean debug = false;
public Cocos2dxGLSurfaceView(Context context) {
super(context);
mRenderer = new Cocos2dxRenderer();
setRenderer(mRenderer);
mTouchController = new MultiTouchController<Void>(this);
}
public boolean onTouchEvent(final MotionEvent event) {
if (mTouchController.onTouchEvent(event)) {
final PointInfo pt = mTouchController.mCurrPt;
final int ids[] = new int[pt.getNumTouchPoints()];
final float xs[] = new float[pt.getNumTouchPoints()];
final float ys[] = new float[pt.getNumTouchPoints()];
// these data are used in ACTION_MOVE and ACTION_CANCEL
final int pointerNumber = event.getPointerCount();
final int[] ids = new int[pointerNumber];
final float[] xs = new float[pointerNumber];
final float[] ys = new float[pointerNumber];
for (int i = 0; i < pt.getNumTouchPoints(); i++) {
ids[i] = pt.getPointerIds()[i];
xs[i] = pt.getXs()[i];
ys[i] = pt.getYs()[i];
Log.d(TAG,
"ACTION: " + pt.getAction() + "id[i]="
+ pt.getPointerIds()[i] + "x[i]= "
+ pt.getXs()[i] + " y[i]= " + pt.getYs()[i]);
}
switch (pt.getAction()) {
case MotionEvent.ACTION_DOWN:
case 261:
case MotionEvent.ACTION_POINTER_DOWN:
Log.d(TAG, "ACTION_DOWN");
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionDown(ids, xs, ys);
}
});
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "ACTION_MOVE");
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionMove(ids, xs, ys);
}
});
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
Log.d(TAG, "ACTION_UP");
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionUp(ids, xs, ys);
}
});
break;
case MotionEvent.ACTION_CANCEL:
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionCancel(ids, xs, ys);
}
});
break;
}
return true;
for (int i = 0; i < pointerNumber; i++) {
ids[i] = event.getPointerId(i);
xs[i] = event.getX(i);
ys[i] = event.getY(i);
}
return false;
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
final int idPointerDown = event.getAction() >> MotionEvent.ACTION_POINTER_ID_SHIFT;
final float xPointerDown = event.getX(idPointerDown);
final float yPointerDown = event.getY(idPointerDown);
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionDown(idPointerDown, xPointerDown, yPointerDown);
}
});
break;
case MotionEvent.ACTION_DOWN:
// there are only one finger on the screen
final int idDown = event.getPointerId(0);
final float xDown = event.getX(idDown);
final float yDown = event.getY(idDown);
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionDown(idDown, xDown, yDown);
}
});
break;
case MotionEvent.ACTION_MOVE:
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionMove(ids, xs, ys);
}
});
break;
case MotionEvent.ACTION_POINTER_UP:
final int idPointerUp = event.getAction() >> MotionEvent.ACTION_POINTER_ID_SHIFT;
final float xPointerUp = event.getX(idPointerUp);
final float yPointerUp = event.getY(idPointerUp);
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionUp(idPointerUp, xPointerUp, yPointerUp);
}
});
break;
case MotionEvent.ACTION_UP:
// there are only one finger on the screen
final int idUp = event.getPointerId(0);
final float xUp = event.getX(idUp);
final float yUp = event.getY(idUp);
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionUp(idUp, xUp, yUp);
}
});
break;
case MotionEvent.ACTION_CANCEL:
queueEvent(new Runnable() {
@Override
public void run() {
mRenderer.handleActionCancel(ids, xs, ys);
}
});
break;
}
if (debug){
dumpEvent(event);
}
return true;
}
@Override
public Object getDraggableObjectAtPoint(PointInfo touchPoint) {
// TODO Auto-generated method stub
return null;
}
@Override
public void getPositionAndScale(Object obj,
PositionAndScale objPosAndScaleOut) {
// TODO Auto-generated method stub
}
@Override
public boolean setPositionAndScale(Object obj,
PositionAndScale newObjPosAndScale, PointInfo touchPoint) {
// TODO Auto-generated method stub
return false;
}
@Override
public void selectObject(Object obj, PointInfo touchPoint) {
// TODO Auto-generated method stub
// Show an event in the LogCat view, for debugging
private void dumpEvent(MotionEvent event) {
String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" ,
"POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" };
StringBuilder sb = new StringBuilder();
int action = event.getAction();
int actionCode = action & MotionEvent.ACTION_MASK;
sb.append("event ACTION_" ).append(names[actionCode]);
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
sb.append("(pid " ).append(
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
sb.append(")" );
}
sb.append("[" );
for (int i = 0; i < event.getPointerCount(); i++) {
sb.append("#" ).append(i);
sb.append("(pid " ).append(event.getPointerId(i));
sb.append(")=" ).append((int) event.getX(i));
sb.append("," ).append((int) event.getY(i));
if (i + 1 < event.getPointerCount())
sb.append(";" );
}
sb.append("]" );
Log.d(TAG, sb.toString());
}
}

View File

@ -39,12 +39,12 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
last = now;
}
public void handleActionDown(int[] id, float[] x, float[] y)
public void handleActionDown(int id, float x, float y)
{
nativeTouchesBegin(id, x, y);
}
public void handleActionUp(int[] id, float[] x, float[] y)
public void handleActionUp(int id, float x, float y)
{
nativeTouchesEnd(id, x, y);
}
@ -63,8 +63,8 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
animationInterval = (long)(interval * NANOSECONDSPERSECOND);
}
private static native void nativeTouchesBegin(int[] id, float[] x, float[] y);
private static native void nativeTouchesEnd(int[] id, float[] x, float[] y);
private static native void nativeTouchesBegin(int id, float x, float y);
private static native void nativeTouchesEnd(int id, float x, float y);
private static native void nativeTouchesMove(int[] id, float[] x, float[] y);
private static native void nativeTouchesCancel(int[] id, float[] x, float[] y);
private static native void nativeRender();

View File

@ -1,812 +0,0 @@
package org.cocos2dx.lib.touch.metalev.multitouch.controller;
/**
* MultiTouchController.java
*
* Author: Luke Hutchison (luke.hutch@mit.edu)
* Please drop me an email if you use this code so I can list your project here!
*
* Usage:
* <code>
* public class MyMTView extends View implements MultiTouchObjectCanvas<PinchWidgetType> {
*
* private MultiTouchController<PinchWidgetType> multiTouchController = new MultiTouchController<PinchWidgetType>(this);
*
* // Pass touch events to the MT controller
* public boolean onTouchEvent(MotionEvent event) {
* return multiTouchController.onTouchEvent(event);
* }
*
* // ... then implement the MultiTouchObjectCanvas interface here, see details in the comments of that interface.
* }
* </code>
*
* Changelog:
* 2010-06-09 v1.5.1 Some API changes to make it possible to selectively update or not update scale / rotation.
* Fixed anisotropic zoom. Cleaned up rotation code. Added more comments. Better var names. (LH)
* 2010-06-09 v1.4 Added ability to track pinch rotation (Mickael Despesse, author of "Face Frenzy") and anisotropic pinch-zoom (LH)
* 2010-06-09 v1.3.3 Bugfixes for Android-2.1; added optional debug info (LH)
* 2010-06-09 v1.3 Ported to Android-2.2 (handle ACTION_POINTER_* actions); fixed several bugs; refactoring; documentation (LH)
* 2010-05-17 v1.2.1 Dual-licensed under Apache and GPL licenses
* 2010-02-18 v1.2 Support for compilation under Android 1.5/1.6 using introspection (mmin, author of handyCalc)
* 2010-01-08 v1.1.1 Bugfixes to Cyanogen's patch that only showed up in more complex uses of controller (LH)
* 2010-01-06 v1.1 Modified for official level 5 MT API (Cyanogen)
* 2009-01-25 v1.0 Original MT controller, released for hacked G1 kernel (LH)
*
* Planned features:
* - Add inertia (flick-pinch-zoom or flick-scroll)
*
* Known usages:
* - Mickael Despesse's "Face Frenzy" face distortion app, to be published to the Market soon
* - Yuan Chin's fork of ADW Launcher to support multitouch
* - David Byrne's fractal viewing app Fractoid
* - mmin's handyCalc calculator
* - My own "MultiTouch Visualizer 2" in the Market
* - Formerly: The browser in cyanogenmod (and before that, JesusFreke), and other firmwares like dwang5. This usage has been
* replaced with official pinch/zoom in Maps, Browser and Gallery[3D] as of API level 5.
*
* License:
* Dual-licensed under the Apache License v2 and the GPL v2.
*/
import java.lang.reflect.Method;
import android.util.Log;
import android.view.MotionEvent;
/**
* A class that simplifies the implementation of multitouch in applications. Subclass this and read the fields here as needed in subclasses.
*
* @author Luke Hutchison
*/
public class MultiTouchController<T> {
/**
* Time in ms required after a change in event status (e.g. putting down or lifting off the second finger) before events actually do anything --
* helps eliminate noisy jumps that happen on change of status
*/
private static final long EVENT_SETTLE_TIME_INTERVAL = 20;
/**
* The biggest possible abs val of the change in x or y between multitouch events (larger dx/dy events are ignored) -- helps eliminate jumps in
* pointer position on finger 2 up/down.
*/
private static final float MAX_MULTITOUCH_POS_JUMP_SIZE = 30.0f;
/**
* The biggest possible abs val of the change in multitouchWidth or multitouchHeight between multitouch events (larger-jump events are ignored) --
* helps eliminate jumps in pointer position on finger 2 up/down.
*/
private static final float MAX_MULTITOUCH_DIM_JUMP_SIZE = 40.0f;
/** The smallest possible distance between multitouch points (used to avoid div-by-zero errors and display glitches) */
private static final float MIN_MULTITOUCH_SEPARATION = 30.0f;
/** The max number of touch points that can be present on the screen at once */
public static final int MAX_TOUCH_POINTS = 5;
/** Generate tons of log entries for debugging */
public static final boolean DEBUG = false;
// ----------------------------------------------------------------------------------------------------------------------
MultiTouchObjectCanvas<T> objectCanvas;
/** The current touch point */
public PointInfo mCurrPt;
/** The previous touch point */
private PointInfo mPrevPt;
/** Fields extracted from mCurrPt */
private float mCurrPtX, mCurrPtY, mCurrPtDiam, mCurrPtWidth, mCurrPtHeight, mCurrPtAng;
/**
* Extract fields from mCurrPt, respecting the update* fields of mCurrPt. This just avoids code duplication. I hate that Java doesn't support
* higher-order functions, tuples or multiple return values from functions.
*/
private void extractCurrPtInfo() {
// Get new drag/pinch params. Only read multitouch fields that are needed,
// to avoid unnecessary computation (diameter and angle are expensive operations).
mCurrPtX = mCurrPt.getX();
mCurrPtY = mCurrPt.getY();
mCurrPtDiam = Math.max(MIN_MULTITOUCH_SEPARATION * .71f, !mCurrXform.updateScale ? 0.0f : mCurrPt.getMultiTouchDiameter());
mCurrPtWidth = Math.max(MIN_MULTITOUCH_SEPARATION, !mCurrXform.updateScaleXY ? 0.0f : mCurrPt.getMultiTouchWidth());
mCurrPtHeight = Math.max(MIN_MULTITOUCH_SEPARATION, !mCurrXform.updateScaleXY ? 0.0f : mCurrPt.getMultiTouchHeight());
mCurrPtAng = !mCurrXform.updateAngle ? 0.0f : mCurrPt.getMultiTouchAngle();
}
// ----------------------------------------------------------------------------------------------------------------------
/** Whether to handle single-touch events/drags before multi-touch is initiated or not; if not, they are handled by subclasses */
private boolean handleSingleTouchEvents;
/** The object being dragged/stretched */
private T selectedObject = null;
/** Current position and scale of the dragged object */
private PositionAndScale mCurrXform = new PositionAndScale();
/** Drag/pinch start time and time to ignore spurious events until (to smooth over event noise) */
private long mSettleStartTime, mSettleEndTime;
/** Conversion from object coords to screen coords */
private float startPosX, startPosY;
/** Conversion between scale and width, and object angle and start pinch angle */
private float startScaleOverPinchDiam, startAngleMinusPinchAngle;
/** Conversion between X scale and width, and Y scale and height */
private float startScaleXOverPinchWidth, startScaleYOverPinchHeight;
// ----------------------------------------------------------------------------------------------------------------------
/** No touch points down. */
private static final int MODE_NOTHING = 0;
/** One touch point down, dragging an object. */
private static final int MODE_DRAG = 1;
/** Two or more touch points down, stretching/rotating an object using the first two touch points. */
private static final int MODE_PINCH = 2;
/** Current drag mode */
private int mMode = MODE_NOTHING;
// ----------------------------------------------------------------------------------------------------------------------
/** Constructor that sets handleSingleTouchEvents to true */
public MultiTouchController(MultiTouchObjectCanvas<T> objectCanvas) {
this(objectCanvas, true);
}
/** Full constructor */
public MultiTouchController(MultiTouchObjectCanvas<T> objectCanvas, boolean handleSingleTouchEvents) {
this.mCurrPt = new PointInfo();
this.mPrevPt = new PointInfo();
this.handleSingleTouchEvents = handleSingleTouchEvents;
this.objectCanvas = objectCanvas;
}
// ------------------------------------------------------------------------------------
/**
* Whether to handle single-touch events/drags before multi-touch is initiated or not; if not, they are handled by subclasses. Default: true
*/
protected void setHandleSingleTouchEvents(boolean handleSingleTouchEvents) {
this.handleSingleTouchEvents = handleSingleTouchEvents;
}
/**
* Whether to handle single-touch events/drags before multi-touch is initiated or not; if not, they are handled by subclasses. Default: true
*/
protected boolean getHandleSingleTouchEvents() {
return handleSingleTouchEvents;
}
// ------------------------------------------------------------------------------------
public static final boolean multiTouchSupported;
private static Method m_getPointerCount;
private static Method m_getPointerId;
private static Method m_getPressure;
private static Method m_getHistoricalX;
private static Method m_getHistoricalY;
private static Method m_getHistoricalPressure;
private static Method m_getX;
private static Method m_getY;
private static int ACTION_POINTER_UP = 6;
private static int ACTION_POINTER_INDEX_SHIFT = 8;
static {
boolean succeeded = false;
try {
// Android 2.0.1 stuff:
m_getPointerCount = MotionEvent.class.getMethod("getPointerCount");
m_getPointerId = MotionEvent.class.getMethod("getPointerId", Integer.TYPE);
m_getPressure = MotionEvent.class.getMethod("getPressure", Integer.TYPE);
m_getHistoricalX = MotionEvent.class.getMethod("getHistoricalX", Integer.TYPE, Integer.TYPE);
m_getHistoricalY = MotionEvent.class.getMethod("getHistoricalY", Integer.TYPE, Integer.TYPE);
m_getHistoricalPressure = MotionEvent.class.getMethod("getHistoricalPressure", Integer.TYPE, Integer.TYPE);
m_getX = MotionEvent.class.getMethod("getX", Integer.TYPE);
m_getY = MotionEvent.class.getMethod("getY", Integer.TYPE);
succeeded = true;
} catch (Exception e) {
Log.e("MultiTouchController", "static initializer failed", e);
}
multiTouchSupported = succeeded;
if (multiTouchSupported) {
// Android 2.2+ stuff (the original Android 2.2 consts are declared above,
// and these actions aren't used previous to Android 2.2):
try {
ACTION_POINTER_UP = MotionEvent.class.getField("ACTION_POINTER_UP").getInt(null);
ACTION_POINTER_INDEX_SHIFT = MotionEvent.class.getField("ACTION_POINTER_INDEX_SHIFT").getInt(null);
} catch (Exception e) {
}
}
}
// ------------------------------------------------------------------------------------
private static final float[] xVals = new float[MAX_TOUCH_POINTS];
private static final float[] yVals = new float[MAX_TOUCH_POINTS];
private static final float[] pressureVals = new float[MAX_TOUCH_POINTS];
private static final int[] pointerIds = new int[MAX_TOUCH_POINTS];
/** Process incoming touch events */
public boolean onTouchEvent(MotionEvent event) {
try {
int pointerCount = multiTouchSupported ? (Integer) m_getPointerCount.invoke(event) : 1;
if (DEBUG)
Log.i("MultiTouch", "Got here 1 - " + multiTouchSupported + " " + mMode + " " + handleSingleTouchEvents + " " + pointerCount);
if (mMode == MODE_NOTHING && !handleSingleTouchEvents && pointerCount == 1)
// Not handling initial single touch events, just pass them on
return false;
if (DEBUG)
Log.i("MultiTouch", "Got here 2");
// Handle history first (we sometimes get history with ACTION_MOVE events)
int action = event.getAction();
int histLen = event.getHistorySize() / pointerCount;
for (int histIdx = 0; histIdx <= histLen; histIdx++) {
// Read from history entries until histIdx == histLen, then read from current event
boolean processingHist = histIdx < histLen;
if (!multiTouchSupported || pointerCount == 1) {
// Use single-pointer methods -- these are needed as a special case (for some weird reason) even if
// multitouch is supported but there's only one touch point down currently -- event.getX(0) etc. throw
// an exception if there's only one point down.
if (DEBUG)
Log.i("MultiTouch", "Got here 3");
xVals[0] = processingHist ? event.getHistoricalX(histIdx) : event.getX();
yVals[0] = processingHist ? event.getHistoricalY(histIdx) : event.getY();
pressureVals[0] = processingHist ? event.getHistoricalPressure(histIdx) : event.getPressure();
} else {
// Read x, y and pressure of each pointer
if (DEBUG)
Log.i("MultiTouch", "Got here 4");
int numPointers = Math.min(pointerCount, MAX_TOUCH_POINTS);
if (DEBUG && pointerCount > MAX_TOUCH_POINTS)
Log.i("MultiTouch", "Got more pointers than MAX_TOUCH_POINTS");
for (int ptrIdx = 0; ptrIdx < numPointers; ptrIdx++) {
int ptrId = (Integer) m_getPointerId.invoke(event, ptrIdx);
pointerIds[ptrIdx] = ptrId;
// N.B. if pointerCount == 1, then the following methods throw an array index out of range exception,
// and the code above is therefore required not just for Android 1.5/1.6 but also for when there is
// only one touch point on the screen -- pointlessly inconsistent :(
xVals[ptrIdx] = (Float) (processingHist ? m_getHistoricalX.invoke(event, ptrIdx, histIdx) : m_getX.invoke(event, ptrIdx));
yVals[ptrIdx] = (Float) (processingHist ? m_getHistoricalY.invoke(event, ptrIdx, histIdx) : m_getY.invoke(event, ptrIdx));
pressureVals[ptrIdx] = (Float) (processingHist ? m_getHistoricalPressure.invoke(event, ptrIdx, histIdx) : m_getPressure
.invoke(event, ptrIdx));
}
}
// Decode event
decodeTouchEvent(pointerCount, xVals, yVals, pressureVals, pointerIds, //
/* action = */processingHist ? MotionEvent.ACTION_MOVE : action, //
/* down = */processingHist ? true : action != MotionEvent.ACTION_UP //
&& (action & ((1 << ACTION_POINTER_INDEX_SHIFT) - 1)) != ACTION_POINTER_UP //
&& action != MotionEvent.ACTION_CANCEL, //
processingHist ? event.getHistoricalEventTime(histIdx) : event.getEventTime());
}
return true;
} catch (Exception e) {
// In case any of the introspection stuff fails (it shouldn't)
Log.e("MultiTouchController", "onTouchEvent() failed", e);
return false;
}
}
private void decodeTouchEvent(int pointerCount, float[] x, float[] y, float[] pressure, int[] pointerIds, int action, boolean down, long eventTime) {
if (DEBUG)
Log.i("MultiTouch", "Got here 5 - " + pointerCount + " " + action + " " + down);
// Swap curr/prev points
PointInfo tmp = mPrevPt;
mPrevPt = mCurrPt;
mCurrPt = tmp;
// Overwrite old prev point
mCurrPt.set(pointerCount, x, y, pressure, pointerIds, action, down, eventTime);
multiTouchController();
}
// ------------------------------------------------------------------------------------
/** Start dragging/pinching, or reset drag/pinch to current point if something goes out of range */
private void anchorAtThisPositionAndScale() {
if (selectedObject == null)
return;
// Get selected object's current position and scale
objectCanvas.getPositionAndScale(selectedObject, mCurrXform);
// Figure out the object coords of the drag start point's screen coords.
// All stretching should be around this point in object-coord-space.
// Also figure out out ratio between object scale factor and multitouch
// diameter at beginning of drag; same for angle and optional anisotropic
// scale.
float currScaleInv = 1.0f / (!mCurrXform.updateScale ? 1.0f : mCurrXform.scale == 0.0f ? 1.0f : mCurrXform.scale);
extractCurrPtInfo();
startPosX = (mCurrPtX - mCurrXform.xOff) * currScaleInv;
startPosY = (mCurrPtY - mCurrXform.yOff) * currScaleInv;
startScaleOverPinchDiam = mCurrXform.scale / mCurrPtDiam;
startScaleXOverPinchWidth = mCurrXform.scaleX / mCurrPtWidth;
startScaleYOverPinchHeight = mCurrXform.scaleY / mCurrPtHeight;
startAngleMinusPinchAngle = mCurrXform.angle - mCurrPtAng;
}
/** Drag/stretch/rotate the selected object using the current touch position(s) relative to the anchor position(s). */
private void performDragOrPinch() {
// Don't do anything if we're not dragging anything
if (selectedObject == null)
return;
// Calc new position of dragged object
float currScale = !mCurrXform.updateScale ? 1.0f : mCurrXform.scale == 0.0f ? 1.0f : mCurrXform.scale;
extractCurrPtInfo();
float newPosX = mCurrPtX - startPosX * currScale;
float newPosY = mCurrPtY - startPosY * currScale;
float newScale = startScaleOverPinchDiam * mCurrPtDiam;
float newScaleX = startScaleXOverPinchWidth * mCurrPtWidth;
float newScaleY = startScaleYOverPinchHeight * mCurrPtHeight;
float newAngle = startAngleMinusPinchAngle + mCurrPtAng;
// Set the new obj coords, scale, and angle as appropriate (notifying the subclass of the change).
mCurrXform.set(newPosX, newPosY, newScale, newScaleX, newScaleY, newAngle);
boolean success = objectCanvas.setPositionAndScale(selectedObject, mCurrXform, mCurrPt);
if (!success)
; // If we could't set those params, do nothing currently
}
/**
* State-based controller for tracking switches between no-touch, single-touch and multi-touch situations. Includes logic for cleaning up the
* event stream, as events around touch up/down are noisy at least on early Synaptics sensors.
*/
private void multiTouchController() {
if (DEBUG)
Log.i("MultiTouch", "Got here 6 - " + mMode + " " + mCurrPt.getNumTouchPoints() + " " + mCurrPt.isDown() + mCurrPt.isMultiTouch());
switch (mMode) {
case MODE_NOTHING:
// Not doing anything currently
if (mCurrPt.isDown()) {
// Start a new single-point drag
selectedObject = objectCanvas.getDraggableObjectAtPoint(mCurrPt);
if (selectedObject != null) {
// Started a new single-point drag
mMode = MODE_DRAG;
objectCanvas.selectObject(selectedObject, mCurrPt);
anchorAtThisPositionAndScale();
// Don't need any settling time if just placing one finger, there is no noise
mSettleStartTime = mSettleEndTime = mCurrPt.getEventTime();
}
}
break;
case MODE_DRAG:
// Currently in a single-point drag
if (!mCurrPt.isDown()) {
// First finger was released, stop dragging
mMode = MODE_NOTHING;
objectCanvas.selectObject((selectedObject = null), mCurrPt);
} else if (mCurrPt.isMultiTouch()) {
// Point 1 was already down and point 2 was just placed down
mMode = MODE_PINCH;
// Restart the drag with the new drag position (that is at the midpoint between the touchpoints)
anchorAtThisPositionAndScale();
// Need to let events settle before moving things, to help with event noise on touchdown
mSettleStartTime = mCurrPt.getEventTime();
mSettleEndTime = mSettleStartTime + EVENT_SETTLE_TIME_INTERVAL;
} else {
// Point 1 is still down and point 2 did not change state, just do single-point drag to new location
if (mCurrPt.getEventTime() < mSettleEndTime) {
// Ignore the first few events if we just stopped stretching, because if finger 2 was kept down while
// finger 1 is lifted, then point 1 gets mapped to finger 2. Restart the drag from the new position.
anchorAtThisPositionAndScale();
} else {
// Keep dragging, move to new point
performDragOrPinch();
}
}
break;
case MODE_PINCH:
// Two-point pinch-scale/rotate/translate
if (!mCurrPt.isMultiTouch() || !mCurrPt.isDown()) {
// Dropped one or both points, stop stretching
if (!mCurrPt.isDown()) {
// Dropped both points, go back to doing nothing
mMode = MODE_NOTHING;
objectCanvas.selectObject((selectedObject = null), mCurrPt);
} else {
// Just dropped point 2, downgrade to a single-point drag
mMode = MODE_DRAG;
// Restart the pinch with the single-finger position
anchorAtThisPositionAndScale();
// Ignore the first few events after the drop, in case we dropped finger 1 and left finger 2 down
mSettleStartTime = mCurrPt.getEventTime();
mSettleEndTime = mSettleStartTime + EVENT_SETTLE_TIME_INTERVAL;
}
} else {
// Still pinching
if (Math.abs(mCurrPt.getX() - mPrevPt.getX()) > MAX_MULTITOUCH_POS_JUMP_SIZE
|| Math.abs(mCurrPt.getY() - mPrevPt.getY()) > MAX_MULTITOUCH_POS_JUMP_SIZE
|| Math.abs(mCurrPt.getMultiTouchWidth() - mPrevPt.getMultiTouchWidth()) * .5f > MAX_MULTITOUCH_DIM_JUMP_SIZE
|| Math.abs(mCurrPt.getMultiTouchHeight() - mPrevPt.getMultiTouchHeight()) * .5f > MAX_MULTITOUCH_DIM_JUMP_SIZE) {
// Jumped too far, probably event noise, reset and ignore events for a bit
anchorAtThisPositionAndScale();
mSettleStartTime = mCurrPt.getEventTime();
mSettleEndTime = mSettleStartTime + EVENT_SETTLE_TIME_INTERVAL;
} else if (mCurrPt.eventTime < mSettleEndTime) {
// Events have not yet settled, reset
anchorAtThisPositionAndScale();
} else {
// Stretch to new position and size
performDragOrPinch();
}
}
break;
}
if (DEBUG)
Log.i("MultiTouch", "Got here 7 - " + mMode + " " + mCurrPt.getNumTouchPoints() + " " + mCurrPt.isDown() + mCurrPt.isMultiTouch());
}
// ------------------------------------------------------------------------------------
/** A class that packages up all MotionEvent information with all derived multitouch information (if available) */
public static class PointInfo {
// Multitouch information
private int numPoints;
private float[] xs = new float[MAX_TOUCH_POINTS];
private float[] ys = new float[MAX_TOUCH_POINTS];
private float[] pressures = new float[MAX_TOUCH_POINTS];
private int[] pointerIds = new int[MAX_TOUCH_POINTS];
// Midpoint of pinch operations
private float xMid, yMid, pressureMid;
// Width/diameter/angle of pinch operations
private float dx, dy, diameter, diameterSq, angle;
// Whether or not there is at least one finger down (isDown) and/or at least two fingers down (isMultiTouch)
private boolean isDown, isMultiTouch;
// Whether or not these fields have already been calculated, for caching purposes
private boolean diameterSqIsCalculated, diameterIsCalculated, angleIsCalculated;
// Event action code and event time
private int action;
private long eventTime;
// -------------------------------------------------------------------------------------------------------------------------------------------
/** Set all point info */
private void set(int numPoints, float[] x, float[] y, float[] pressure, int[] pointerIds, int action, boolean isDown, long eventTime) {
if (DEBUG)
Log.i("MultiTouch", "Got here 8 - " + +numPoints + " " + x[0] + " " + y[0] + " " + (numPoints > 1 ? x[1] : x[0]) + " "
+ (numPoints > 1 ? y[1] : y[0]) + " " + action + " " + isDown);
this.eventTime = eventTime;
this.action = action;
this.numPoints = numPoints;
for (int i = 0; i < numPoints; i++) {
this.xs[i] = x[i];
this.ys[i] = y[i];
this.pressures[i] = pressure[i];
this.pointerIds[i] = pointerIds[i];
}
this.isDown = isDown;
this.isMultiTouch = numPoints >= 2;
if (isMultiTouch) {
xMid = (x[0] + x[1]) * .5f;
yMid = (y[0] + y[1]) * .5f;
pressureMid = (pressure[0] + pressure[1]) * .5f;
dx = Math.abs(x[1] - x[0]);
dy = Math.abs(y[1] - y[0]);
} else {
// Single-touch event
xMid = x[0];
yMid = y[0];
pressureMid = pressure[0];
dx = dy = 0.0f;
}
// Need to re-calculate the expensive params if they're needed
diameterSqIsCalculated = diameterIsCalculated = angleIsCalculated = false;
}
/**
* Copy all fields from one PointInfo class to another. PointInfo objects are volatile so you should use this if you want to keep track of the
* last touch event in your own code.
*/
public void set(PointInfo other) {
this.numPoints = other.numPoints;
for (int i = 0; i < numPoints; i++) {
this.xs[i] = other.xs[i];
this.ys[i] = other.ys[i];
this.pressures[i] = other.pressures[i];
this.pointerIds[i] = other.pointerIds[i];
}
this.xMid = other.xMid;
this.yMid = other.yMid;
this.pressureMid = other.pressureMid;
this.dx = other.dx;
this.dy = other.dy;
this.diameter = other.diameter;
this.diameterSq = other.diameterSq;
this.angle = other.angle;
this.isDown = other.isDown;
this.action = other.action;
this.isMultiTouch = other.isMultiTouch;
this.diameterIsCalculated = other.diameterIsCalculated;
this.diameterSqIsCalculated = other.diameterSqIsCalculated;
this.angleIsCalculated = other.angleIsCalculated;
this.eventTime = other.eventTime;
}
// -------------------------------------------------------------------------------------------------------------------------------------------
/** True if number of touch points >= 2. */
public boolean isMultiTouch() {
return isMultiTouch;
}
/** Difference between x coords of touchpoint 0 and 1. */
public float getMultiTouchWidth() {
return isMultiTouch ? dx : 0.0f;
}
/** Difference between y coords of touchpoint 0 and 1. */
public float getMultiTouchHeight() {
return isMultiTouch ? dy : 0.0f;
}
/** Fast integer sqrt, by Jim Ulery. Much faster than Math.sqrt() for integers. */
private int julery_isqrt(int val) {
int temp, g = 0, b = 0x8000, bshft = 15;
do {
if (val >= (temp = (((g << 1) + b) << bshft--))) {
g += b;
val -= temp;
}
} while ((b >>= 1) > 0);
return g;
}
/** Calculate the squared diameter of the multitouch event, and cache it. Use this if you don't need to perform the sqrt. */
public float getMultiTouchDiameterSq() {
if (!diameterSqIsCalculated) {
diameterSq = (isMultiTouch ? dx * dx + dy * dy : 0.0f);
diameterSqIsCalculated = true;
}
return diameterSq;
}
/** Calculate the diameter of the multitouch event, and cache it. Uses fast int sqrt but gives accuracy to 1/16px. */
public float getMultiTouchDiameter() {
if (!diameterIsCalculated) {
if (!isMultiTouch) {
diameter = 0.0f;
} else {
// Get 1/16 pixel's worth of subpixel accuracy, works on screens up to 2048x2048
// before we get overflow (at which point you can reduce or eliminate subpix
// accuracy, or use longs in julery_isqrt())
float diamSq = getMultiTouchDiameterSq();
diameter = (diamSq == 0.0f ? 0.0f : (float) julery_isqrt((int) (256 * diamSq)) / 16.0f);
// Make sure diameter is never less than dx or dy, for trig purposes
if (diameter < dx)
diameter = dx;
if (diameter < dy)
diameter = dy;
}
diameterIsCalculated = true;
}
return diameter;
}
/**
* Calculate the angle of a multitouch event, and cache it. Actually gives the smaller of the two angles between the x axis and the line
* between the two touchpoints, so range is [0,Math.PI/2]. Uses Math.atan2().
*/
public float getMultiTouchAngle() {
if (!angleIsCalculated) {
if (!isMultiTouch)
angle = 0.0f;
else
angle = (float) Math.atan2(ys[1] - ys[0], xs[1] - xs[0]);
angleIsCalculated = true;
}
return angle;
}
// -------------------------------------------------------------------------------------------------------------------------------------------
/** Return the total number of touch points */
public int getNumTouchPoints() {
return numPoints;
}
/** Return the X coord of the first touch point if there's only one, or the midpoint between first and second touch points if two or more. */
public float getX() {
return xMid;
}
/** Return the array of X coords -- only the first getNumTouchPoints() of these is defined. */
public float[] getXs() {
return xs;
}
/** Return the X coord of the first touch point if there's only one, or the midpoint between first and second touch points if two or more. */
public float getY() {
return yMid;
}
/** Return the array of Y coords -- only the first getNumTouchPoints() of these is defined. */
public float[] getYs() {
return ys;
}
/**
* Return the array of pointer ids -- only the first getNumTouchPoints() of these is defined. These don't have to be all the numbers from 0 to
* getNumTouchPoints()-1 inclusive, numbers can be skipped if a finger is lifted and the touch sensor is capable of detecting that that
* particular touch point is no longer down. Note that a lot of sensors do not have this capability: when finger 1 is lifted up finger 2
* becomes the new finger 1. However in theory these IDs can correct for that. Convert back to indices using MotionEvent.findPointerIndex().
*/
public int[] getPointerIds() {
return pointerIds;
}
/** Return the pressure the first touch point if there's only one, or the average pressure of first and second touch points if two or more. */
public float getPressure() {
return pressureMid;
}
/** Return the array of pressures -- only the first getNumTouchPoints() of these is defined. */
public float[] getPressures() {
return pressures;
}
// -------------------------------------------------------------------------------------------------------------------------------------------
public boolean isDown() {
return isDown;
}
public int getAction() {
return action;
}
public long getEventTime() {
return eventTime;
}
}
// ------------------------------------------------------------------------------------
/**
* A class that is used to store scroll offsets and scale information for objects that are managed by the multitouch controller
*/
public static class PositionAndScale {
private float xOff, yOff, scale, scaleX, scaleY, angle;
private boolean updateScale, updateScaleXY, updateAngle;
/**
* Set position and optionally scale, anisotropic scale, and/or angle. Where if the corresponding "update" flag is set to false, the field's
* value will not be changed during a pinch operation. If the value is not being updated *and* the value is not used by the client
* application, then the value can just be zero. However if the value is not being updated but the value *is* being used by the client
* application, the value should still be specified and the update flag should be false (e.g. angle of the object being dragged should still
* be specified even if the program is in "resize" mode rather than "rotate" mode).
*/
public void set(float xOff, float yOff, boolean updateScale, float scale, boolean updateScaleXY, float scaleX, float scaleY,
boolean updateAngle, float angle) {
this.xOff = xOff;
this.yOff = yOff;
this.updateScale = updateScale;
this.scale = scale == 0.0f ? 1.0f : scale;
this.updateScaleXY = updateScaleXY;
this.scaleX = scaleX == 0.0f ? 1.0f : scaleX;
this.scaleY = scaleY == 0.0f ? 1.0f : scaleY;
this.updateAngle = updateAngle;
this.angle = angle;
}
/** Set position and optionally scale, anisotropic scale, and/or angle, without changing the "update" flags. */
protected void set(float xOff, float yOff, float scale, float scaleX, float scaleY, float angle) {
this.xOff = xOff;
this.yOff = yOff;
this.scale = scale == 0.0f ? 1.0f : scale;
this.scaleX = scaleX == 0.0f ? 1.0f : scaleX;
this.scaleY = scaleY == 0.0f ? 1.0f : scaleY;
this.angle = angle;
}
public float getXOff() {
return xOff;
}
public float getYOff() {
return yOff;
}
public float getScale() {
return !updateScale ? 1.0f : scale;
}
/** Included in case you want to support anisotropic scaling */
public float getScaleX() {
return !updateScaleXY ? 1.0f : scaleX;
}
/** Included in case you want to support anisotropic scaling */
public float getScaleY() {
return !updateScaleXY ? 1.0f : scaleY;
}
public float getAngle() {
return !updateAngle ? 0.0f : angle;
}
}
// ------------------------------------------------------------------------------------
public static interface MultiTouchObjectCanvas<T> {
/**
* See if there is a draggable object at the current point. Returns the object at the point, or null if nothing to drag. To start a multitouch
* drag/stretch operation, this routine must return some non-null reference to an object. This object is passed into the other methods in this
* interface when they are called.
*
* @param touchPoint
* The point being tested (in object coordinates). Return the topmost object under this point, or if dragging/stretching the whole
* canvas, just return a reference to the canvas.
* @return a reference to the object under the point being tested, or null to cancel the drag operation. If dragging/stretching the whole
* canvas (e.g. in a photo viewer), always return non-null, otherwise the stretch operation won't work.
*/
public T getDraggableObjectAtPoint(PointInfo touchPoint);
/**
* Get the screen coords of the dragged object's origin, and scale multiplier to convert screen coords to obj coords. The job of this routine
* is to call the .set() method on the passed PositionAndScale object to record the initial position and scale of the object (in object
* coordinates) before any dragging/stretching takes place.
*
* @param obj
* The object being dragged/stretched.
* @param objPosAndScaleOut
* Output parameter: You need to call objPosAndScaleOut.set() to record the current position and scale of obj.
*/
public void getPositionAndScale(T obj, PositionAndScale objPosAndScaleOut);
/**
* Callback to update the position and scale (in object coords) of the currently-dragged object.
*
* @param obj
* The object being dragged/stretched.
* @param newObjPosAndScale
* The new position and scale of the object, in object coordinates. Use this to move/resize the object before returning.
* @param touchPoint
* Info about the current touch point, including multitouch information and utilities to calculate and cache multitouch pinch
* diameter etc. (Note: touchPoint is volatile, if you want to keep any fields of touchPoint, you must copy them before the method
* body exits.)
* @return true if setting the position and scale of the object was successful, or false if the position or scale parameters are out of range
* for this object.
*/
public boolean setPositionAndScale(T obj, PositionAndScale newObjPosAndScale, PointInfo touchPoint);
/**
* Select an object at the given point. Can be used to bring the object to top etc. Only called when first touchpoint goes down, not when
* multitouch is initiated. Also called with null on touch-up.
*
* @param obj
* The object being selected by single-touch, or null on touch-up.
* @param touchPoint
* The current touch point.
*/
public void selectObject(T obj, PointInfo touchPoint);
}
}

View File

@ -1 +1 @@
338236875114a0bacedc941ed640ad725f71e061
2950d252aeb110a0d262811b794bdd2ff25c03b6

View File

@ -1 +1 @@
1df0bf26583b2b3cfde43364d98d925393dddb51
9e16647d99e1705b6436f4764cfacc6a478d3715