mirror of https://github.com/axmolengine/axmol.git
Merge branch 'master' of https://github.com/cocos2d/cocos2d-x into 439
Conflicts: cocos2dx/platform/ios/CCFileUtils_ios.mm
This commit is contained in:
commit
7e81c56231
|
@ -8,4 +8,4 @@
|
||||||
# project structure.
|
# project structure.
|
||||||
|
|
||||||
# Project target.
|
# Project target.
|
||||||
target=android-8
|
target=android-7
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
# it is needed for ndk-r5
|
# it is needed for ndk-r5
|
||||||
APP_STL := stlport_static
|
APP_STL := stlport_static
|
||||||
|
|
||||||
|
APP_MODULES := cocos2d cocosdenshion helloworld
|
|
@ -1,119 +1,139 @@
|
||||||
package org.cocos2dx.lib;
|
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.content.Context;
|
||||||
import android.opengl.GLSurfaceView;
|
import android.opengl.GLSurfaceView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
public class Cocos2dxGLSurfaceView extends GLSurfaceView implements
|
public class Cocos2dxGLSurfaceView extends GLSurfaceView{
|
||||||
MultiTouchObjectCanvas {
|
|
||||||
private static final String TAG = Cocos2dxGLSurfaceView.class
|
private static final String TAG = Cocos2dxGLSurfaceView.class
|
||||||
.getCanonicalName();
|
.getCanonicalName();
|
||||||
private MultiTouchController<Void> mTouchController;
|
|
||||||
private Cocos2dxRenderer mRenderer;
|
private Cocos2dxRenderer mRenderer;
|
||||||
|
private final boolean debug = false;
|
||||||
|
|
||||||
public Cocos2dxGLSurfaceView(Context context) {
|
public Cocos2dxGLSurfaceView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
mRenderer = new Cocos2dxRenderer();
|
mRenderer = new Cocos2dxRenderer();
|
||||||
setRenderer(mRenderer);
|
setRenderer(mRenderer);
|
||||||
|
|
||||||
mTouchController = new MultiTouchController<Void>(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onTouchEvent(final MotionEvent event) {
|
public boolean onTouchEvent(final MotionEvent event) {
|
||||||
if (mTouchController.onTouchEvent(event)) {
|
// these data are used in ACTION_MOVE and ACTION_CANCEL
|
||||||
final PointInfo pt = mTouchController.mCurrPt;
|
final int pointerNumber = event.getPointerCount();
|
||||||
final int ids[] = new int[pt.getNumTouchPoints()];
|
final int[] ids = new int[pointerNumber];
|
||||||
final float xs[] = new float[pt.getNumTouchPoints()];
|
final float[] xs = new float[pointerNumber];
|
||||||
final float ys[] = new float[pt.getNumTouchPoints()];
|
final float[] ys = new float[pointerNumber];
|
||||||
|
|
||||||
for (int i = 0; i < pt.getNumTouchPoints(); i++) {
|
for (int i = 0; i < pointerNumber; i++) {
|
||||||
ids[i] = pt.getPointerIds()[i];
|
ids[i] = event.getPointerId(i);
|
||||||
xs[i] = pt.getXs()[i];
|
xs[i] = event.getX(i);
|
||||||
ys[i] = pt.getYs()[i];
|
ys[i] = event.getY(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;
|
|
||||||
}
|
}
|
||||||
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
|
/** Show an event in the LogCat view, for debugging */
|
||||||
public Object getDraggableObjectAtPoint(PointInfo touchPoint) {
|
private void dumpEvent(MotionEvent event) {
|
||||||
// TODO Auto-generated method stub
|
String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" ,
|
||||||
return null;
|
"POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" };
|
||||||
}
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int action = event.getAction();
|
||||||
@Override
|
int actionCode = action & MotionEvent.ACTION_MASK;
|
||||||
public void getPositionAndScale(Object obj,
|
sb.append("event ACTION_" ).append(names[actionCode]);
|
||||||
PositionAndScale objPosAndScaleOut) {
|
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|
||||||
// TODO Auto-generated method stub
|
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
|
||||||
|
sb.append("(pid " ).append(
|
||||||
}
|
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
|
||||||
|
sb.append(")" );
|
||||||
@Override
|
}
|
||||||
public boolean setPositionAndScale(Object obj,
|
sb.append("[" );
|
||||||
PositionAndScale newObjPosAndScale, PointInfo touchPoint) {
|
for (int i = 0; i < event.getPointerCount(); i++) {
|
||||||
// TODO Auto-generated method stub
|
sb.append("#" ).append(i);
|
||||||
return false;
|
sb.append("(pid " ).append(event.getPointerId(i));
|
||||||
}
|
sb.append(")=" ).append((int) event.getX(i));
|
||||||
|
sb.append("," ).append((int) event.getY(i));
|
||||||
@Override
|
if (i + 1 < event.getPointerCount())
|
||||||
public void selectObject(Object obj, PointInfo touchPoint) {
|
sb.append(";" );
|
||||||
// TODO Auto-generated method stub
|
}
|
||||||
|
sb.append("]" );
|
||||||
|
Log.d(TAG, sb.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,12 +39,12 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
|
||||||
last = now;
|
last = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleActionDown(int[] id, float[] x, float[] y)
|
public void handleActionDown(int id, float x, float y)
|
||||||
{
|
{
|
||||||
nativeTouchesBegin(id, x, 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);
|
nativeTouchesEnd(id, x, y);
|
||||||
}
|
}
|
||||||
|
@ -63,8 +63,8 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
|
||||||
animationInterval = (long)(interval * NANOSECONDSPERSECOND);
|
animationInterval = (long)(interval * NANOSECONDSPERSECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void nativeTouchesBegin(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 nativeTouchesEnd(int id, float x, float y);
|
||||||
private static native void nativeTouchesMove(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 nativeTouchesCancel(int[] id, float[] x, float[] y);
|
||||||
private static native void nativeRender();
|
private static native void nativeRender();
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +1 @@
|
||||||
fe4815b00d6e0564ee73979cc062a3b81ee0ae79
|
d09725f4302ca8fa1f0ce71afbe4ad0ab9418713
|
|
@ -45,6 +45,7 @@ files
|
||||||
("cocos2dx/cocoa")
|
("cocos2dx/cocoa")
|
||||||
[cocoa]
|
[cocoa]
|
||||||
"*.cpp"
|
"*.cpp"
|
||||||
|
"*.h"
|
||||||
|
|
||||||
("cocos2dx/effects")
|
("cocos2dx/effects")
|
||||||
[effects]
|
[effects]
|
||||||
|
|
|
@ -25,6 +25,7 @@ cocoa/CCAffineTransform.cpp \
|
||||||
cocoa/CCGeometry.cpp \
|
cocoa/CCGeometry.cpp \
|
||||||
cocoa/CCAutoreleasePool.cpp \
|
cocoa/CCAutoreleasePool.cpp \
|
||||||
cocoa/CCData.cpp \
|
cocoa/CCData.cpp \
|
||||||
|
cocoa/CCNS.cpp \
|
||||||
cocoa/CCObject.cpp \
|
cocoa/CCObject.cpp \
|
||||||
cocoa/CCSet.cpp \
|
cocoa/CCSet.cpp \
|
||||||
cocoa/CCZone.cpp \
|
cocoa/CCZone.cpp \
|
||||||
|
@ -64,7 +65,6 @@ platform/CCCommon.cpp \
|
||||||
platform/CCParticleSystemPoint_mobile.cpp \
|
platform/CCParticleSystemPoint_mobile.cpp \
|
||||||
platform/CCTransition_mobile.cpp \
|
platform/CCTransition_mobile.cpp \
|
||||||
platform/platform.cpp \
|
platform/platform.cpp \
|
||||||
platform/android/CCNS_android.cpp \
|
|
||||||
platform/android/CCEGLView_android.cpp \
|
platform/android/CCEGLView_android.cpp \
|
||||||
platform/android/CCAccelerometer_android.cpp \
|
platform/android/CCAccelerometer_android.cpp \
|
||||||
platform/android/CCApplication_android.cpp \
|
platform/android/CCApplication_android.cpp \
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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__
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ private:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CCDictionary<std::string, CCSpriteFrame*> *m_pSpriteFrames;
|
CCDictionary<std::string, CCSpriteFrame*> *m_pSpriteFrames;
|
||||||
CCDictionary<std::string, CCSpriteFrame*> *m_pSpriteFramesAliases;
|
CCDictionary<std::string, CCString*> *m_pSpriteFramesAliases;
|
||||||
};
|
};
|
||||||
}//namespace cocos2d
|
}//namespace cocos2d
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "platform/CCNS.h"
|
#include "cocoa/CCNS.h"
|
||||||
#include "CCDirector.h"
|
#include "CCDirector.h"
|
||||||
#include "CCScene.h"
|
#include "CCScene.h"
|
||||||
#include "CCMutableArray.h"
|
#include "CCMutableArray.h"
|
||||||
|
|
|
@ -24,7 +24,7 @@ THE SOFTWARE.
|
||||||
|
|
||||||
#include "CCFileUtils.h"
|
#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 <stack>
|
||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
|
@ -55,12 +55,18 @@ public:
|
||||||
std::stack<CCDictionary<std::string, CCObject*>*> m_tDictStack;
|
std::stack<CCDictionary<std::string, CCObject*>*> m_tDictStack;
|
||||||
std::string m_sCurKey;///< parsed key
|
std::string m_sCurKey;///< parsed key
|
||||||
CCSAXState m_tState;
|
CCSAXState m_tState;
|
||||||
|
bool m_bInArray;
|
||||||
|
CCMutableArray<CCObject*> *m_pArray;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CCDictMaker()
|
CCDictMaker()
|
||||||
{
|
{
|
||||||
m_pRootDict = NULL;
|
m_pRootDict = NULL;
|
||||||
m_pCurDict = NULL;
|
m_pCurDict = NULL;
|
||||||
m_tState = SAX_NONE;
|
m_tState = SAX_NONE;
|
||||||
|
|
||||||
|
m_pArray = NULL;
|
||||||
|
m_bInArray = false;
|
||||||
}
|
}
|
||||||
~CCDictMaker()
|
~CCDictMaker()
|
||||||
{
|
{
|
||||||
|
@ -119,6 +125,11 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (sName == "array")
|
||||||
|
{
|
||||||
|
m_bInArray = true;
|
||||||
|
m_pArray = new CCMutableArray<CCObject*>();
|
||||||
|
}
|
||||||
m_tState = SAX_NONE;
|
m_tState = SAX_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,6 +145,14 @@ public:
|
||||||
m_pCurDict = (CCDictionary<std::string, CCObject*>*)(m_tDictStack.top());
|
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;
|
m_tState = SAX_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +175,15 @@ public:
|
||||||
case SAX_STRING:
|
case SAX_STRING:
|
||||||
{
|
{
|
||||||
CCAssert(!m_sCurKey.empty(), "not found key : <integet/real>");
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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__
|
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,8 @@ public:
|
||||||
std::stack<CCDictionary<std::string, CCObject*>*> m_tDictStack;
|
std::stack<CCDictionary<std::string, CCObject*>*> m_tDictStack;
|
||||||
std::string m_sCurKey;///< parsed key
|
std::string m_sCurKey;///< parsed key
|
||||||
CCSAXState m_tState;
|
CCSAXState m_tState;
|
||||||
|
bool m_bInArray;
|
||||||
|
CCMutableArray<CCObject*> *m_pArray;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CCDictMaker()
|
CCDictMaker()
|
||||||
|
@ -60,6 +62,9 @@ public:
|
||||||
m_pRootDict = NULL;
|
m_pRootDict = NULL;
|
||||||
m_pCurDict = NULL;
|
m_pCurDict = NULL;
|
||||||
m_tState = SAX_NONE;
|
m_tState = SAX_NONE;
|
||||||
|
|
||||||
|
m_pArray = NULL;
|
||||||
|
m_bInArray = false;
|
||||||
}
|
}
|
||||||
~CCDictMaker()
|
~CCDictMaker()
|
||||||
{
|
{
|
||||||
|
@ -80,91 +85,115 @@ public:
|
||||||
|
|
||||||
void startElement(void *ctx, const XML_Char *name, const XML_Char **atts)
|
void startElement(void *ctx, const XML_Char *name, const XML_Char **atts)
|
||||||
{
|
{
|
||||||
CCDictMaker *pMaker = this;
|
|
||||||
std::string sName((char*)name);
|
std::string sName((char*)name);
|
||||||
if( sName == "dict" )
|
if( sName == "dict" )
|
||||||
{
|
{
|
||||||
CCDictionary<std::string, CCObject*> *pNewDict = new CCDictionary<std::string, CCObject*>();
|
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();
|
pNewDict->autorelease();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CCAssert(pMaker->m_pCurDict && !pMaker->m_sCurKey.empty(), "");
|
CCAssert(m_pCurDict && !m_sCurKey.empty(), "");
|
||||||
pMaker->m_pCurDict->setObject(pNewDict, pMaker->m_sCurKey);
|
m_pCurDict->setObject(pNewDict, m_sCurKey);
|
||||||
pNewDict->release();
|
pNewDict->release();
|
||||||
pMaker->m_sCurKey.clear();
|
m_sCurKey.clear();
|
||||||
}
|
}
|
||||||
pMaker->m_pCurDict = pNewDict;
|
m_pCurDict = pNewDict;
|
||||||
pMaker->m_tDictStack.push(pMaker->m_pCurDict);
|
m_tDictStack.push(m_pCurDict);
|
||||||
pMaker->m_tState = SAX_DICT;
|
m_tState = SAX_DICT;
|
||||||
}
|
}
|
||||||
else if(sName == "key")
|
else if(sName == "key")
|
||||||
{
|
{
|
||||||
pMaker->m_tState = SAX_KEY;
|
m_tState = SAX_KEY;
|
||||||
}
|
}
|
||||||
else if(sName == "integer")
|
else if(sName == "integer")
|
||||||
{
|
{
|
||||||
pMaker->m_tState = SAX_INT;
|
m_tState = SAX_INT;
|
||||||
}
|
}
|
||||||
else if(sName == "real")
|
else if(sName == "real")
|
||||||
{
|
{
|
||||||
pMaker->m_tState = SAX_REAL;
|
m_tState = SAX_REAL;
|
||||||
}
|
}
|
||||||
else if(sName == "string")
|
else if(sName == "string")
|
||||||
{
|
{
|
||||||
pMaker->m_tState = SAX_STRING;
|
m_tState = SAX_STRING;
|
||||||
}
|
}
|
||||||
else
|
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)
|
void endElement(void *ctx, const XML_Char *name)
|
||||||
{
|
{
|
||||||
CCDictMaker * pMaker = this;
|
|
||||||
std::string sName((char*)name);
|
std::string sName((char*)name);
|
||||||
if( sName == "dict" )
|
if( sName == "dict" )
|
||||||
{
|
{
|
||||||
pMaker->m_tDictStack.pop();
|
m_tDictStack.pop();
|
||||||
if ( !pMaker->m_tDictStack.empty() )
|
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)
|
void textHandler(void *ctx, const XML_Char *ch, int len)
|
||||||
{
|
{
|
||||||
CCDictMaker * pMaker = this;
|
if (m_tState == SAX_NONE)
|
||||||
if (pMaker->m_tState == SAX_NONE)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CCString *pText = new CCString();
|
CCString *pText = new CCString();
|
||||||
pText->m_sString = std::string((char*)ch,0,len);
|
pText->m_sString = std::string((char*)ch,0,len);
|
||||||
|
|
||||||
switch(pMaker->m_tState)
|
switch(m_tState)
|
||||||
{
|
{
|
||||||
case SAX_KEY:
|
case SAX_KEY:
|
||||||
{
|
{
|
||||||
pMaker->m_sCurKey = pText->m_sString;
|
m_sCurKey = pText->m_sString;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SAX_INT:
|
case SAX_INT:
|
||||||
case SAX_REAL:
|
case SAX_REAL:
|
||||||
{
|
{
|
||||||
CCAssert(!pMaker->m_sCurKey.empty(), "not found real : <integet/real>");
|
CCAssert(!m_sCurKey.empty(), "not found real : <integet/real>");
|
||||||
pMaker->m_pCurDict->setObject(pText, pMaker->m_sCurKey);
|
if (m_bInArray)
|
||||||
|
{
|
||||||
|
m_pArray->addObject(pText);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pCurDict->setObject(pText, m_sCurKey);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SAX_STRING:
|
case SAX_STRING:
|
||||||
{
|
{
|
||||||
CCAssert(!pMaker->m_sCurKey.empty(), "not found string");
|
CCAssert(!m_sCurKey.empty(), "not found string");
|
||||||
pMaker->m_pCurDict->setObject(pText, pMaker->m_sCurKey);
|
if (m_bInArray)
|
||||||
|
{
|
||||||
|
m_pArray->addObject(pText);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_pCurDict->setObject(pText, m_sCurKey);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -30,11 +30,13 @@ THE SOFTWARE.
|
||||||
#include "CCGeometry.h"
|
#include "CCGeometry.h"
|
||||||
#include "platform/android/CCAccelerometer_android.h"
|
#include "platform/android/CCAccelerometer_android.h"
|
||||||
#include <android/log.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 LOG_TAG "Cocos2dJni"
|
||||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
|
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define LOGD(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace cocos2d;
|
using namespace cocos2d;
|
||||||
|
|
||||||
|
@ -42,8 +44,7 @@ extern "C"
|
||||||
{
|
{
|
||||||
|
|
||||||
#define MAX_TOUCHES 5
|
#define MAX_TOUCHES 5
|
||||||
static cocos2d::CCTouch *s_pTouches[MAX_TOUCHES] = { NULL };
|
static CCTouch *s_pTouches[MAX_TOUCHES] = { NULL };
|
||||||
static cocos2d::CCSet s_set;
|
|
||||||
|
|
||||||
// handle accelerometer changes
|
// handle accelerometer changes
|
||||||
|
|
||||||
|
@ -58,84 +59,54 @@ extern "C"
|
||||||
timeStamp);
|
timeStamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle touch event
|
// handle touch event
|
||||||
|
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesBegin(JNIEnv* env, jobject thiz, jint id, jfloat x, jfloat y)
|
||||||
void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeTouchesBegin(JNIEnv* env, jobject thiz, jintArray ids, jfloatArray xs, jfloatArray ys)
|
|
||||||
{
|
{
|
||||||
int size = env->GetArrayLength(ids);
|
|
||||||
jint id[size];
|
|
||||||
jfloat x[size];
|
|
||||||
jfloat y[size];
|
|
||||||
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
|
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
|
||||||
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
|
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
|
||||||
|
CCSet set;
|
||||||
|
|
||||||
env->GetIntArrayRegion(ids, 0, size, id);
|
CCTouch *pTouch = s_pTouches[id];
|
||||||
env->GetFloatArrayRegion(xs, 0, size, x);
|
if (! pTouch)
|
||||||
env->GetFloatArrayRegion(ys, 0, size, y);
|
{
|
||||||
|
LOGD("Beginning touches with id: %d, x=%f, y=%f", id, x, y);
|
||||||
|
|
||||||
for( int i = 0 ; i < size ; i++ ) {
|
pTouch = new CCTouch();
|
||||||
cocos2d::CCTouch* pTouch = s_pTouches[id[i]];
|
pTouch->SetTouchInfo(0, (x - rcRect.origin.x) / fScreenScaleFactor, (y - rcRect.origin.y) / fScreenScaleFactor);
|
||||||
LOGD("Should create new pTouch if null: %d", pTouch);
|
s_pTouches[id] = pTouch;
|
||||||
if (!pTouch)
|
set.addObject(pTouch);
|
||||||
{
|
|
||||||
pTouch = new cocos2d::CCTouch;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGD("Beginning touches with id: %d, x=%f, y=%f", id[i], x[i], y[i]);
|
cocos2d::CCDirector::sharedDirector()->getOpenGLView()->getDelegate()->touchesBegan(&set, NULL);
|
||||||
pTouch->SetTouchInfo(0, (x[i] - rcRect.origin.x) / fScreenScaleFactor ,
|
}
|
||||||
(y[i] - rcRect.origin.y) / fScreenScaleFactor);
|
else
|
||||||
|
{
|
||||||
s_set.addObject(pTouch);
|
LOGD("Beginnig touches with id: %d error", id);
|
||||||
s_pTouches[id[i]] = pTouch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
|
||||||
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
|
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);
|
|
||||||
|
|
||||||
/* Add to the set to send to the director */
|
/* Add to the set to send to the director */
|
||||||
for( int i = 0 ; i < size ; i++ ) {
|
CCTouch* pTouch = s_pTouches[id];
|
||||||
cocos2d::CCTouch* pTouch = s_pTouches[id[i]];
|
if (pTouch)
|
||||||
LOGD("Ending touches with id: %d, x=%f, y=%f", id[i], x[i], y[i]);
|
{
|
||||||
if (pTouch)
|
LOGD("Ending touches with id: %d, x=%f, y=%f", id, x, y);
|
||||||
{
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 */
|
// release the object
|
||||||
for( int i = 0 ; i < size ; i++ ) {
|
pTouch->release();
|
||||||
cocos2d::CCTouch* pTouch = s_pTouches[id[i]];
|
s_pTouches[id] = NULL;
|
||||||
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!");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
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)
|
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];
|
jfloat y[size];
|
||||||
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
|
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
|
||||||
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
|
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
|
||||||
|
CCSet set;
|
||||||
|
|
||||||
env->GetIntArrayRegion(ids, 0, size, id);
|
env->GetIntArrayRegion(ids, 0, size, id);
|
||||||
env->GetFloatArrayRegion(xs, 0, size, x);
|
env->GetFloatArrayRegion(xs, 0, size, x);
|
||||||
|
@ -158,11 +130,17 @@ extern "C"
|
||||||
{
|
{
|
||||||
pTouch->SetTouchInfo(0, (x[i] - rcRect.origin.x) / fScreenScaleFactor ,
|
pTouch->SetTouchInfo(0, (x[i] - rcRect.origin.x) / fScreenScaleFactor ,
|
||||||
(y[i] - rcRect.origin.y) / 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)
|
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];
|
jfloat y[size];
|
||||||
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
|
CCRect rcRect = CCEGLView::sharedOpenGLView().getViewPort();
|
||||||
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
|
float fScreenScaleFactor = CCEGLView::sharedOpenGLView().getScreenScaleFactor();
|
||||||
|
CCSet set;
|
||||||
|
|
||||||
env->GetIntArrayRegion(ids, 0, size, id);
|
env->GetIntArrayRegion(ids, 0, size, id);
|
||||||
env->GetFloatArrayRegion(xs, 0, size, x);
|
env->GetFloatArrayRegion(xs, 0, size, x);
|
||||||
|
@ -184,12 +163,13 @@ extern "C"
|
||||||
{
|
{
|
||||||
pTouch->SetTouchInfo(0, (x[i] - rcRect.origin.x) / fScreenScaleFactor ,
|
pTouch->SetTouchInfo(0, (x[i] - rcRect.origin.x) / fScreenScaleFactor ,
|
||||||
(y[i] - rcRect.origin.y) / fScreenScaleFactor);
|
(y[i] - rcRect.origin.y) / fScreenScaleFactor);
|
||||||
s_set.addObject(pTouch);
|
set.addObject(pTouch);
|
||||||
s_pTouches[id[i]] = NULL;
|
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)
|
void Java_org_cocos2dx_lib_Cocos2dxActivity_nativeSetPaths(JNIEnv* env, jobject thiz, jstring apkPath)
|
||||||
|
|
|
@ -115,155 +115,208 @@ static const char* static_fullPathFromRelativePath(const char *pszRelativePath)
|
||||||
// do not convert an absolute path (starting with '/')
|
// do not convert an absolute path (starting with '/')
|
||||||
NSString *relPath = [NSString stringWithUTF8String: pszRelativePath];
|
NSString *relPath = [NSString stringWithUTF8String: pszRelativePath];
|
||||||
NSString *fullpath = nil;
|
NSString *fullpath = nil;
|
||||||
|
|
||||||
// only if it is not an absolute path
|
// only if it is not an absolute path
|
||||||
if( ! [relPath isAbsolutePath] )
|
if( ! [relPath isAbsolutePath] )
|
||||||
{
|
{
|
||||||
NSString *file = [relPath lastPathComponent];
|
NSString *file = [relPath lastPathComponent];
|
||||||
NSString *imageDirectory = [relPath stringByDeletingLastPathComponent];
|
NSString *imageDirectory = [relPath stringByDeletingLastPathComponent];
|
||||||
|
|
||||||
fullpath = [[NSBundle mainBundle] pathForResource:file
|
fullpath = [[NSBundle mainBundle] pathForResource:file
|
||||||
ofType:nil
|
ofType:nil
|
||||||
inDirectory:imageDirectory];
|
inDirectory:imageDirectory];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fullpath == nil)
|
if (fullpath == nil)
|
||||||
fullpath = relPath;
|
fullpath = relPath;
|
||||||
|
|
||||||
fullpath = getDoubleResolutionImage(fullpath);
|
fullpath = getDoubleResolutionImage(fullpath);
|
||||||
|
|
||||||
return [fullpath UTF8String];
|
return [fullpath UTF8String];
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace cocos2d {
|
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,
|
m_pRootDict = NULL;
|
||||||
SAX_KEY,
|
m_pCurDict = NULL;
|
||||||
SAX_DICT,
|
m_tState = SAX_NONE;
|
||||||
SAX_INT,
|
|
||||||
SAX_REAL,
|
|
||||||
SAX_STRING
|
|
||||||
}CCSAXState;
|
|
||||||
|
|
||||||
class CCDictMaker : public CCSAXDelegator
|
m_pArray = NULL;
|
||||||
|
m_bInArray = false;
|
||||||
|
}
|
||||||
|
~CCDictMaker()
|
||||||
{
|
{
|
||||||
public:
|
}
|
||||||
CCDictionary<std::string, CCObject*> *m_pRootDict;
|
CCDictionary<std::string, CCObject*> *dictionaryWithContentsOfFile(const char *pFileName)
|
||||||
CCDictionary<std::string, CCObject*> *m_pCurDict;
|
{
|
||||||
std::stack<CCDictionary<std::string, CCObject*>*> m_tDictStack;
|
CCSAXParser parser;
|
||||||
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;
|
|
||||||
|
|
||||||
if (false == parser.init("UTF-8"))
|
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)
|
|
||||||
{
|
{
|
||||||
std::string sName((char*)name);
|
return NULL;
|
||||||
if( sName == "dict" )
|
}
|
||||||
|
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*>();
|
m_pRootDict = pNewDict;
|
||||||
if(! m_pRootDict)
|
pNewDict->autorelease();
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
else
|
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;
|
||||||
}
|
}
|
||||||
|
else if(sName == "key")
|
||||||
void endElement(void *ctx, const char *name)
|
|
||||||
{
|
{
|
||||||
std::string sName((char*)name);
|
m_tState = SAX_KEY;
|
||||||
if( sName == "dict" )
|
}
|
||||||
|
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();
|
m_bInArray = true;
|
||||||
if ( !m_tDictStack.empty() )
|
m_pArray = new CCMutableArray<CCObject*>();
|
||||||
{
|
|
||||||
m_pCurDict = (CCDictionary<std::string, CCObject*>*)(m_tDictStack.top());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
m_tState = SAX_NONE;
|
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
|
// record the resource path
|
||||||
static char s_pszResourcePath[MAX_PATH] = {0};
|
static char s_pszResourcePath[MAX_PATH] = {0};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -211,6 +211,14 @@
|
||||||
RelativePath="..\cocoa\CCGeometry.cpp"
|
RelativePath="..\cocoa\CCGeometry.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\cocoa\CCNS.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\cocoa\CCNS.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\cocoa\CCObject.cpp"
|
RelativePath="..\cocoa\CCObject.cpp"
|
||||||
>
|
>
|
||||||
|
@ -775,10 +783,6 @@
|
||||||
RelativePath="..\platform\CCNode_mobile.cpp"
|
RelativePath="..\platform\CCNode_mobile.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\platform\CCNS.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\platform\CCParticleSystemPoint_mobile.cpp"
|
RelativePath="..\platform\CCParticleSystemPoint_mobile.cpp"
|
||||||
>
|
>
|
||||||
|
@ -858,10 +862,6 @@
|
||||||
RelativePath="..\platform\win32\CCEGLView_win32.h"
|
RelativePath="..\platform\win32\CCEGLView_win32.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\platform\win32\CCNS_win32.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
|
|
|
@ -53,6 +53,7 @@ OBJECTS = \
|
||||||
$(OBJECTS_DIR)/CCAutoreleasePool.o \
|
$(OBJECTS_DIR)/CCAutoreleasePool.o \
|
||||||
$(OBJECTS_DIR)/CCData.o \
|
$(OBJECTS_DIR)/CCData.o \
|
||||||
$(OBJECTS_DIR)/CCGeometry.o \
|
$(OBJECTS_DIR)/CCGeometry.o \
|
||||||
|
$(OBJECTS_DIR)/CCNS.o \
|
||||||
$(OBJECTS_DIR)/CCObject.o \
|
$(OBJECTS_DIR)/CCObject.o \
|
||||||
$(OBJECTS_DIR)/CCSet.o \
|
$(OBJECTS_DIR)/CCSet.o \
|
||||||
$(OBJECTS_DIR)/CCZone.o \
|
$(OBJECTS_DIR)/CCZone.o \
|
||||||
|
@ -95,7 +96,6 @@ OBJECTS = \
|
||||||
$(OBJECTS_DIR)/CCAccelerometer_wophone.o \
|
$(OBJECTS_DIR)/CCAccelerometer_wophone.o \
|
||||||
$(OBJECTS_DIR)/CCApplication_wophone.o \
|
$(OBJECTS_DIR)/CCApplication_wophone.o \
|
||||||
$(OBJECTS_DIR)/CCEGLView_wophone.o \
|
$(OBJECTS_DIR)/CCEGLView_wophone.o \
|
||||||
$(OBJECTS_DIR)/CCNS_wophone.o \
|
|
||||||
$(OBJECTS_DIR)/CCAnimation.o \
|
$(OBJECTS_DIR)/CCAnimation.o \
|
||||||
$(OBJECTS_DIR)/CCAnimationCache.o \
|
$(OBJECTS_DIR)/CCAnimationCache.o \
|
||||||
$(OBJECTS_DIR)/CCSprite.o \
|
$(OBJECTS_DIR)/CCSprite.o \
|
||||||
|
@ -204,6 +204,9 @@ $(OBJECTS_DIR)/CCData.o : ../cocoa/CCData.cpp
|
||||||
$(OBJECTS_DIR)/CCGeometry.o : ../cocoa/CCGeometry.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
|
$(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
|
$(OBJECTS_DIR)/CCObject.o : ../cocoa/CCObject.cpp
|
||||||
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(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
|
$(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
|
$(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
|
$(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
|
$(CXX) -c $(CXX_FLAGS) $(INCLUDE_PATH) $(LAST_INCLUDE_PATH) -o $(OBJECTS_DIR)/CCAnimation.o ../sprite_nodes/CCAnimation.cpp
|
||||||
|
|
||||||
|
|
|
@ -880,6 +880,14 @@
|
||||||
RelativePath="..\cocoa\CCGeometry.cpp"
|
RelativePath="..\cocoa\CCGeometry.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\cocoa\CCNS.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\cocoa\CCNS.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\cocoa\CCObject.cpp"
|
RelativePath="..\cocoa\CCObject.cpp"
|
||||||
>
|
>
|
||||||
|
@ -968,10 +976,6 @@
|
||||||
RelativePath="..\platform\CCNode_mobile.cpp"
|
RelativePath="..\platform\CCNode_mobile.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\platform\CCNS.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\platform\CCParticleSystemPoint_mobile.h"
|
RelativePath="..\platform\CCParticleSystemPoint_mobile.h"
|
||||||
>
|
>
|
||||||
|
@ -1051,10 +1055,6 @@
|
||||||
RelativePath="..\platform\wophone\CCEGLView_wophone.h"
|
RelativePath="..\platform\wophone\CCEGLView_wophone.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\platform\wophone\CCNS_wophone.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\platform\wophone\NewDeleteOp.cpp"
|
RelativePath="..\platform\wophone\NewDeleteOp.cpp"
|
||||||
>
|
>
|
||||||
|
|
|
@ -25,7 +25,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
THE SOFTWARE.
|
THE SOFTWARE.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "platform/CCNS.h"
|
#include "cocoa/CCNS.h"
|
||||||
#include "ccMacros.h"
|
#include "ccMacros.h"
|
||||||
#include "CCTextureCache.h"
|
#include "CCTextureCache.h"
|
||||||
#include "CCSpriteFrameCache.h"
|
#include "CCSpriteFrameCache.h"
|
||||||
|
@ -58,7 +58,7 @@ void CCSpriteFrameCache::purgeSharedSpriteFrameCache(void)
|
||||||
bool CCSpriteFrameCache::init(void)
|
bool CCSpriteFrameCache::init(void)
|
||||||
{
|
{
|
||||||
m_pSpriteFrames= new CCDictionary<std::string, CCSpriteFrame*>();
|
m_pSpriteFrames= new CCDictionary<std::string, CCSpriteFrame*>();
|
||||||
m_pSpriteFramesAliases = new CCDictionary<std::string, CCSpriteFrame*>();
|
m_pSpriteFramesAliases = new CCDictionary<std::string, CCString*>();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,10 +155,6 @@ void CCSpriteFrameCache::addSpriteFramesWithDictionary(CCDictionary<std::string,
|
||||||
} else
|
} else
|
||||||
if (format == 3)
|
if (format == 3)
|
||||||
{
|
{
|
||||||
/// @todo what's the format look like?
|
|
||||||
assert(false);
|
|
||||||
return;
|
|
||||||
/*
|
|
||||||
// get values
|
// get values
|
||||||
CCSize spriteSize = CCSizeFromString(valueForKey("spriteSize", frameDict));
|
CCSize spriteSize = CCSizeFromString(valueForKey("spriteSize", frameDict));
|
||||||
CCPoint spriteOffset = CCPointFromString(valueForKey("spriteOffset", frameDict));
|
CCPoint spriteOffset = CCPointFromString(valueForKey("spriteOffset", frameDict));
|
||||||
|
@ -167,19 +163,28 @@ void CCSpriteFrameCache::addSpriteFramesWithDictionary(CCDictionary<std::string,
|
||||||
bool textureRotated = atoi(valueForKey("textureRotated", frameDict)) == 0;
|
bool textureRotated = atoi(valueForKey("textureRotated", frameDict)) == 0;
|
||||||
|
|
||||||
// get aliases
|
// 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) )
|
CCString * frameKey = new CCString(key.c_str());
|
||||||
{
|
for (iter = aliases->begin(); iter != aliases->end(); iter++)
|
||||||
std::string value = ((CCString*)alias->objectForKey(key))->m_sString();
|
{
|
||||||
if (m_pSpriteFramesAliases->objectForKey(value))
|
std::string oneAlias = ((CCString*) (*iter))->m_sString;
|
||||||
{
|
if (m_pSpriteFramesAliases->objectForKey(oneAlias))
|
||||||
CCLOG("cocos2d: WARNING: an alias with name %s already exists", value.c_str());
|
{
|
||||||
}
|
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
|
// add sprite frame
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
130df27ea38ccc20118cc71eeebcccba4db470a4
|
f02925523f965e430f8e881c5244ee080899fb99
|
|
@ -1 +1 @@
|
||||||
8c07d2ef5449fd386fca2f52f4347112006db602
|
96413c22c2a8542a63d1887b42fb9ec2ab1b15d3
|
|
@ -1 +1 @@
|
||||||
2b6d1b09f7d781bb57632c801d23aec310bfe676
|
3a2dfc8ad67562d58622125a30fa53a55c717e23
|
|
@ -8,4 +8,4 @@
|
||||||
# project structure.
|
# project structure.
|
||||||
|
|
||||||
# Project target.
|
# Project target.
|
||||||
target=android-8
|
target=android-7
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
# it is needed for ndk-r5
|
# it is needed for ndk-r5
|
||||||
APP_STL := stlport_static
|
APP_STL := stlport_static
|
||||||
APP_ABI := armeabi armeabi-v7a
|
APP_ABI := armeabi armeabi-v7a
|
||||||
|
|
||||||
|
APP_MODULES := cocos2d cocosdenshion chipmunk box2d tests
|
||||||
|
|
|
@ -1,119 +1,139 @@
|
||||||
package org.cocos2dx.lib;
|
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.content.Context;
|
||||||
import android.opengl.GLSurfaceView;
|
import android.opengl.GLSurfaceView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
|
||||||
public class Cocos2dxGLSurfaceView extends GLSurfaceView implements
|
public class Cocos2dxGLSurfaceView extends GLSurfaceView{
|
||||||
MultiTouchObjectCanvas {
|
|
||||||
private static final String TAG = Cocos2dxGLSurfaceView.class
|
private static final String TAG = Cocos2dxGLSurfaceView.class
|
||||||
.getCanonicalName();
|
.getCanonicalName();
|
||||||
private MultiTouchController<Void> mTouchController;
|
|
||||||
private Cocos2dxRenderer mRenderer;
|
private Cocos2dxRenderer mRenderer;
|
||||||
|
private final boolean debug = false;
|
||||||
|
|
||||||
public Cocos2dxGLSurfaceView(Context context) {
|
public Cocos2dxGLSurfaceView(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
mRenderer = new Cocos2dxRenderer();
|
mRenderer = new Cocos2dxRenderer();
|
||||||
setRenderer(mRenderer);
|
setRenderer(mRenderer);
|
||||||
|
|
||||||
mTouchController = new MultiTouchController<Void>(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onTouchEvent(final MotionEvent event) {
|
public boolean onTouchEvent(final MotionEvent event) {
|
||||||
if (mTouchController.onTouchEvent(event)) {
|
// these data are used in ACTION_MOVE and ACTION_CANCEL
|
||||||
final PointInfo pt = mTouchController.mCurrPt;
|
final int pointerNumber = event.getPointerCount();
|
||||||
final int ids[] = new int[pt.getNumTouchPoints()];
|
final int[] ids = new int[pointerNumber];
|
||||||
final float xs[] = new float[pt.getNumTouchPoints()];
|
final float[] xs = new float[pointerNumber];
|
||||||
final float ys[] = new float[pt.getNumTouchPoints()];
|
final float[] ys = new float[pointerNumber];
|
||||||
|
|
||||||
for (int i = 0; i < pt.getNumTouchPoints(); i++) {
|
for (int i = 0; i < pointerNumber; i++) {
|
||||||
ids[i] = pt.getPointerIds()[i];
|
ids[i] = event.getPointerId(i);
|
||||||
xs[i] = pt.getXs()[i];
|
xs[i] = event.getX(i);
|
||||||
ys[i] = pt.getYs()[i];
|
ys[i] = event.getY(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;
|
|
||||||
}
|
}
|
||||||
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
|
// Show an event in the LogCat view, for debugging
|
||||||
public Object getDraggableObjectAtPoint(PointInfo touchPoint) {
|
private void dumpEvent(MotionEvent event) {
|
||||||
// TODO Auto-generated method stub
|
String names[] = { "DOWN" , "UP" , "MOVE" , "CANCEL" , "OUTSIDE" ,
|
||||||
return null;
|
"POINTER_DOWN" , "POINTER_UP" , "7?" , "8?" , "9?" };
|
||||||
}
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int action = event.getAction();
|
||||||
@Override
|
int actionCode = action & MotionEvent.ACTION_MASK;
|
||||||
public void getPositionAndScale(Object obj,
|
sb.append("event ACTION_" ).append(names[actionCode]);
|
||||||
PositionAndScale objPosAndScaleOut) {
|
if (actionCode == MotionEvent.ACTION_POINTER_DOWN
|
||||||
// TODO Auto-generated method stub
|
|| actionCode == MotionEvent.ACTION_POINTER_UP) {
|
||||||
|
sb.append("(pid " ).append(
|
||||||
}
|
action >> MotionEvent.ACTION_POINTER_ID_SHIFT);
|
||||||
|
sb.append(")" );
|
||||||
@Override
|
}
|
||||||
public boolean setPositionAndScale(Object obj,
|
sb.append("[" );
|
||||||
PositionAndScale newObjPosAndScale, PointInfo touchPoint) {
|
for (int i = 0; i < event.getPointerCount(); i++) {
|
||||||
// TODO Auto-generated method stub
|
sb.append("#" ).append(i);
|
||||||
return false;
|
sb.append("(pid " ).append(event.getPointerId(i));
|
||||||
}
|
sb.append(")=" ).append((int) event.getX(i));
|
||||||
|
sb.append("," ).append((int) event.getY(i));
|
||||||
@Override
|
if (i + 1 < event.getPointerCount())
|
||||||
public void selectObject(Object obj, PointInfo touchPoint) {
|
sb.append(";" );
|
||||||
// TODO Auto-generated method stub
|
}
|
||||||
|
sb.append("]" );
|
||||||
|
Log.d(TAG, sb.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,12 +39,12 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
|
||||||
last = now;
|
last = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleActionDown(int[] id, float[] x, float[] y)
|
public void handleActionDown(int id, float x, float y)
|
||||||
{
|
{
|
||||||
nativeTouchesBegin(id, x, 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);
|
nativeTouchesEnd(id, x, y);
|
||||||
}
|
}
|
||||||
|
@ -63,8 +63,8 @@ public class Cocos2dxRenderer implements GLSurfaceView.Renderer {
|
||||||
animationInterval = (long)(interval * NANOSECONDSPERSECOND);
|
animationInterval = (long)(interval * NANOSECONDSPERSECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void nativeTouchesBegin(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 nativeTouchesEnd(int id, float x, float y);
|
||||||
private static native void nativeTouchesMove(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 nativeTouchesCancel(int[] id, float[] x, float[] y);
|
||||||
private static native void nativeRender();
|
private static native void nativeRender();
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1 +1 @@
|
||||||
338236875114a0bacedc941ed640ad725f71e061
|
2950d252aeb110a0d262811b794bdd2ff25c03b6
|
|
@ -1 +1 @@
|
||||||
1df0bf26583b2b3cfde43364d98d925393dddb51
|
9e16647d99e1705b6436f4764cfacc6a478d3715
|
Loading…
Reference in New Issue