code:
/* Copyright (c) 2007 Scott Lembcke
 *
 * 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.
 */

/*
 * The previous WalkBot demo I designed was fairly disappointing, so I implemented
 * the mechanism that Theo Jansen uses in his kinetic sculptures. Brilliant.
 * Read more here: http://en.wikipedia.org/wiki/Theo_Jansen
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "chipmunk.h"
#include "drawSpace.h"
#include "ChipmunkDemo.h"

static cpSpace *space;

static cpConstraint *motor;

static void
update(int ticks)
{
	cpFloat coef = (2.0f + arrowDirection.y)/3.0f;
	cpFloat rate = arrowDirection.x*10.0f*coef;
	cpSimpleMotorSetRate(motor, rate);
	motor->maxForce = (rate) ? 100000.0f : 0.0f;

	int steps = 3;
	cpFloat dt = 1.0f/60.0f/(cpFloat)steps;

	for(int i=0; i<steps; i++){
		cpSpaceStep(space, dt);
	}
}

static cpFloat seg_radius = 3.0f;

static void
make_leg(cpFloat side, cpFloat offset, cpBody *chassis, cpBody *crank, cpVect anchor)
{
	cpVect a, b;
	cpShape *shape;

	cpFloat leg_mass = 1.0f;

	// make leg
	a = cpvzero, b = cpv(0.0f, side);
	cpBody *upper_leg = cpBodyNew(leg_mass, cpMomentForSegment(leg_mass, a, b));
	upper_leg->p = cpv(offset, 0.0f);
	cpSpaceAddBody(space, upper_leg);
	cpSpaceAddShape(space, cpSegmentShapeNew(upper_leg, a, b, seg_radius));
	cpSpaceAddConstraint(space, cpPivotJointNew2(chassis, upper_leg, cpv(offset, 0.0f), cpvzero));

	// lower leg
	a = cpvzero, b = cpv(0.0f, -1.0f*side);
	cpBody *lower_leg = cpBodyNew(leg_mass, cpMomentForSegment(leg_mass, a, b));
	lower_leg->p = cpv(offset, -side);
	cpSpaceAddBody(space, lower_leg);
	shape = cpSegmentShapeNew(lower_leg, a, b, seg_radius);
	shape->group = 1;
	cpSpaceAddShape(space, shape);
	shape = cpCircleShapeNew(lower_leg, seg_radius*2.0f, b);
	shape->group = 1;
	shape->e = 0.0f; shape->u = 1.0f;
	cpSpaceAddShape(space, shape);
	cpSpaceAddConstraint(space, cpPinJointNew(chassis, lower_leg, cpv(offset, 0.0f), cpvzero));

	cpSpaceAddConstraint(space, cpGearJointNew(upper_leg, lower_leg, 0.0f, 1.0f));

	cpConstraint *constraint;
	cpFloat diag = cpfsqrt(side*side + offset*offset);

	constraint = cpPinJointNew(crank, upper_leg, anchor, cpv(0.0f, side));
	cpPinJointSetDist(constraint, diag);
	cpSpaceAddConstraint(space, constraint);
	constraint = cpPinJointNew(crank, lower_leg, anchor, cpvzero);
	cpPinJointSetDist(constraint, diag);
	cpSpaceAddConstraint(space, constraint);
}

static cpSpace *
init(void)
{
	space = cpSpaceNew();

	cpResetShapeIdCounter();

	space = cpSpaceNew();
	space->iterations = 20;
	space->gravity = cpv(0,-500);

	cpBody *staticBody = &space->staticBody;
	cpShape *shape;
	cpVect a, b;

	// Create segments around the edge of the screen.
	shape = cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f);
	shape->e = 1.0f; shape->u = 1.0f;
	shape->layers = NOT_GRABABLE_MASK;
	cpSpaceAddShape(space, shape);

	shape = cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f);
	shape->e = 1.0f; shape->u = 1.0f;
	shape->layers = NOT_GRABABLE_MASK;
	cpSpaceAddShape(space, shape);

	shape = cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f);
	shape->e = 1.0f; shape->u = 1.0f;
	shape->layers = NOT_GRABABLE_MASK;
	cpSpaceAddShape(space, shape);

	cpFloat offset = 30.0f;

	// make chassis
	cpFloat chassis_mass = 2.0f;
	a = cpv(-offset, 0.0f), b = cpv(offset, 0.0f);
	cpBody *chassis = cpBodyNew(chassis_mass, cpMomentForSegment(chassis_mass, a, b));
	cpSpaceAddBody(space, chassis);
	shape = cpSegmentShapeNew(chassis, a, b, seg_radius);
	shape->group = 1;
	cpSpaceAddShape(space, shape);

	// make crank
	cpFloat crank_mass = 1.0f;
	cpFloat crank_radius = 13.0f;
	cpBody *crank = cpBodyNew(crank_mass, cpMomentForCircle(crank_mass, crank_radius, 0.0f, cpvzero));
	cpSpaceAddBody(space, crank);
	shape = cpCircleShapeNew(crank, crank_radius, cpvzero);
	shape->group = 1;
	cpSpaceAddShape(space, shape);
	cpSpaceAddConstraint(space, cpPivotJointNew2(chassis, crank, cpvzero, cpvzero));

	cpFloat side = 30.0f;

	int num_legs = 2;
	for(int i=0; i<num_legs; i++){
		make_leg(side,  offset, chassis, crank, cpvmult(cpvforangle((cpFloat)(2*i+0)/num_legs*(cpFloat)M_PI), crank_radius));
		make_leg(side, -offset, chassis, crank, cpvmult(cpvforangle((cpFloat)(2*i+1)/num_legs*(cpFloat)M_PI), crank_radius));
	}

	motor = cpSimpleMotorNew(chassis, crank, 6.0f);
	cpSpaceAddConstraint(space, motor);

	return space;
}

static void
destroy(void)
{
	cpSpaceFreeChildren(space);
	cpSpaceFree(space);
}

chipmunkDemo TheoJansen = {
	"Theo Jansen Machine",
	NULL,
	init,
	update,
	destroy,
};


code:
/* Copyright (c) 2007 Scott Lembcke
 *
 * 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 <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "chipmunk.h"
#include "drawSpace.h"
#include "ChipmunkDemo.h"

static cpSpace *space;
static cpBody *staticBody;

static void
update(int ticks)
{
	int steps = 3;
	cpFloat dt = 1.0f/60.0f/(cpFloat)steps;

	for(int i=0; i<steps; i++){
		cpSpaceStep(space, dt);

		// Manually update the position of the static shape so that
		// the box rotates.
		cpBodyUpdatePosition(staticBody, dt);

		// Because the box was added as a static shape and we moved it
		// we need to manually rehash the static spatial hash.
		cpSpaceRehashStatic(space);
	}
}

static cpSpace *
init(void)
{
	staticBody = cpBodyNew(INFINITY, INFINITY);

	cpResetShapeIdCounter();

	space = cpSpaceNew();
	cpSpaceResizeActiveHash(space, 40.0f, 999);
	cpSpaceResizeStaticHash(space, 40.0f, 99);
	space->gravity = cpv(0, -600);

	cpBody *body;
	cpShape *shape;

	// Vertexes for the bricks
	int num = 4;
	cpVect verts[] = {
		cpv(-30,-15),
		cpv(-30, 15),
		cpv( 30, 15),
		cpv( 30,-15),
	};

	// Set up the static box.
	cpVect a = cpv(-200, -200);
	cpVect b = cpv(-200,  200);
	cpVect c = cpv( 200,  200);
	cpVect d = cpv( 200, -200);

	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, a, b, 0.0f));
	shape->e = 1.0f; shape->u = 1.0f;
	shape->layers = NOT_GRABABLE_MASK;

	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, b, c, 0.0f));
	shape->e = 1.0f; shape->u = 1.0f;
	shape->layers = NOT_GRABABLE_MASK;

	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, c, d, 0.0f));
	shape->e = 1.0f; shape->u = 1.0f;
	shape->layers = NOT_GRABABLE_MASK;

	shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, d, a, 0.0f));
	shape->e = 1.0f; shape->u = 1.0f;
	shape->layers = NOT_GRABABLE_MASK;

	// Give the box a little spin.
	// Because staticBody is never added to the space, we will need to
	// update it ourselves. (see above).
	// NOTE: Normally you would want to add the segments as normal and not static shapes.
	// I'm just doing it to demonstrate the cpSpaceRehashStatic() function.
	staticBody->w = 0.4f;

	// Add the bricks.
	for(int i=0; i<3; i++){
		for(int j=0; j<7; j++){
			body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts, cpvzero)));
			body->p = cpv(i*60 - 150, j*30 - 150);

			shape = cpSpaceAddShape(space, cpPolyShapeNew(body, num, verts, cpvzero));
			shape->e = 0.0f; shape->u = 0.7f;
		}
	}

	return space;
}

static void
destroy(void)
{
	cpBodyFree(staticBody);
	cpSpaceFreeChildren(space);
	cpSpaceFree(space);
}

chipmunkDemo Tumble = {
	"Tumble",
	NULL,
	init,
	update,
	destroy,
};

license: mit


code:
/* Copyright (c) 2007 Scott Lembcke
 *
 * 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 <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#include "chipmunk.h"
#include "chipmunk_unsafe.h"
#include "drawSpace.h"
#include "ChipmunkDemo.h"

static cpSpace *space;

#define NUM_CIRCLES 30
static cpShape *circles[NUM_CIRCLES];
static cpFloat circleRadius = 30.0f;

static void
update(int ticks)
{
	if(arrowDirection.y){
		circleRadius = cpfmax(10.0f, circleRadius + arrowDirection.y);

		for(int i=0; i<NUM_CIRCLES; i++){
			circles[i]->body->m = cpMomentForCircle(1.0f, 0.0f, circleRadius, cpvzero);
			cpCircleShapeSetRadius(circles[i], circleRadius);
		}
	}

	int steps = 1;
	cpFloat dt = 1.0f/60.0f/(cpFloat)steps;

	for(int i=0; i<steps; i++){
		cpSpaceStep(space, dt);
	}
}

static cpSpace *
init(void)
{
	cpResetShapeIdCounter();

	space = cpSpaceNew();
	space->iterations = 5;
	space->gravity = cpv(0, -100);

	cpSpaceResizeStaticHash(space, 40.0f, 999);
	cpSpaceResizeActiveHash(space, 30.0f, 2999);

	cpBody *body, *staticBody = &space->staticBody;
	cpShape *shape;

	shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f));
	shape->e = 1.0f; shape->u = 1.0f;
	shape->layers = NOT_GRABABLE_MASK;

	shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f));
	shape->e = 1.0f; shape->u = 1.0f;
	shape->layers = NOT_GRABABLE_MASK;

	shape = cpSpaceAddStaticShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f));
	shape->e = 1.0f; shape->u = 1.0f;
	shape->layers = NOT_GRABABLE_MASK;

	for(int i=0; i<NUM_CIRCLES; i++){
		body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForCircle(1.0f, 0.0f, circleRadius, cpvzero)));
		body->p = cpvmult(cpv(frand()*2.0f - 1.0f, frand()*2.0f - 1.0f), circleRadius*5.0f);

		circles[i] = shape = cpSpaceAddShape(space, cpCircleShapeNew(body, circleRadius, cpvzero));
		shape->e = 0.0f; shape->u = 1.0f;
	}

	strcat(messageString,
		"chipmunk_unsafe.h Contains functions for changing shapes, but they can cause severe stability problems if used incorrectly.\n"
		"Shape changes occur as instantaneous changes to position without an accompanying velocity change. USE WITH CAUTION!");
	return space;
}

static void
destroy(void)
{
	cpSpaceFreeChildren(space);
	cpSpaceFree(space);
}

chipmunkDemo UnsafeOps = {
	"Unsafe Operations",
	NULL,
	init,
	update,
	destroy,
};


code:
/* Copyright (c) 2007 Scott Lembcke
 *
 * 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.
 */

/*
	IMPORTANT - READ ME!

	This file sets up a simple interface that the individual demos can use to get
	a Chipmunk space running and draw what's in it. In order to keep the Chipmunk
	examples clean and simple, they contain no graphics code. All drawing is done
	by accessing the Chipmunk structures at a very low level. It is NOT
	recommended to write a game or application this way as it does not scale
	beyond simple shape drawing and is very dependent on implementation details
	about Chipmunk which may change with little to no warning.
*/

#include "cocos2d.h"
#include "chipmunk.h"
#include "drawSpace.h"
#include "cocos2dChipmunkDemo.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <limits.h>

#define SLEEP_TICKS 16

#if (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)

#define glOrthof glOrtho
#endif

//extern chipmunkDemo Test;
extern chipmunkDemo LogoSmash;
extern chipmunkDemo Simple;
extern chipmunkDemo PyramidStack;
extern chipmunkDemo Plink;
extern chipmunkDemo Tumble;
extern chipmunkDemo PyramidTopple;
extern chipmunkDemo Bounce;
extern chipmunkDemo Planet;
extern chipmunkDemo Springies;
extern chipmunkDemo Pump;
extern chipmunkDemo TheoJansen;
extern chipmunkDemo MagnetsElectric;
extern chipmunkDemo UnsafeOps;
extern chipmunkDemo Query;
extern chipmunkDemo OneWay;
extern chipmunkDemo Player;
extern chipmunkDemo Sensors;
extern chipmunkDemo Joints;
extern chipmunkDemo Tank;

//extern chipmunkDemo Test;

static chipmunkDemo *demos[] = {
	&LogoSmash,
	&Simple,
	&PyramidStack,
	&Plink,
	&Tumble,
	&PyramidTopple,
	&Bounce,
	&Planet,
	&Springies,
	&Pump,
	&TheoJansen,
	&MagnetsElectric,
	&UnsafeOps,
	&Query,
	&OneWay,
	&Player,
	&Sensors,
	&Joints,
	&Tank,
};

static int maxDemos = sizeof(demos) / sizeof(demos[0]);

static const int demoCount = sizeof(demos)/sizeof(chipmunkDemo *);
static chipmunkDemo *currDemo = NULL;
static const int firstDemoIndex = 'a' - 'a';

static int ticks = 0;
static cpSpace *space;

cpVect mousePoint;
cpVect mousePoint_last;
cpBody *mouseBody = NULL;
cpConstraint *mouseJoint = NULL;

char messageString[1024] = {};

int key_up = 0;
int key_down = 0;
int key_left = 0;
int key_right = 0;

cpVect arrowDirection = {};

drawSpaceOptions options = {
	0,
	0,
	1,
	4.0f,
	0.0f,
	1.5f,
};

static void
drawString(int x, int y, const char *str)
{
//	glColor3f(0.0f, 0.0f, 0.0f);
//	glRasterPos2i(x, y);
//
//	for(int i=0, len=strlen(str); i<len; i++){
//		if(str[i] == '\n'){
//			y -= 16;
//			glRasterPos2i(x, y);
//		} else if(str[i] == '*'){ // print out the last demo key
//			glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, 'A' + demoCount - 1);
//		} else {
//			glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, str[i]);
//		}
//	}
}

static void
drawInstructions()
{
	drawString(-300, 220,
			   "Controls:\n"
			   "A - * Switch demos. (return restarts)\n"
			   "Use the mouse to grab objects.\n"
			   "Arrow keys control some demos.\n"
			   "\\ enables anti-aliasing.\n"
			   "- toggles spatial hash visualization.\n"
			   "= toggles bounding boxes."
			   );
}

static int maxArbiters = 0;
static int maxPoints = 0;
static int maxConstraints = 0;

static void
drawInfo()
{
	int arbiters = space->arbiters->num;
	int points = 0;

	for(int i=0; i<arbiters; i++)
		points += ((cpArbiter *)(space->arbiters->arr[i]))->numContacts;

	int constraints = (space->constraints->num + points)*(space->iterations + space->elasticIterations);

	maxArbiters = arbiters > maxArbiters ? arbiters : maxArbiters;
	maxPoints = points > maxPoints ? points : maxPoints;
	maxConstraints = constraints > maxConstraints ? constraints : maxConstraints;

	char buffer[1024];
	const char *format =
	"Arbiters: %d (%d) - "
	"Contact Points: %d (%d)\n"
	"Other Constraints: %d, Iterations: %d\n"
	"Constraints x Iterations: %d (%d)\n"
	"KE:% 5.2e";

	cpArray *bodies = space->bodies;
	cpFloat ke = 0.0f;
	for(int i=0; i<bodies->num; i++){
		cpBody *body = (cpBody *)bodies->arr[i];
		if(body->m == INFINITY || body->i == INFINITY) continue;

		ke += body->m*cpvdot(body->v, body->v) + body->i*body->w*body->w;
	}

	sprintf(buffer, format,
			arbiters, maxArbiters,
			points, maxPoints,
			space->constraints->num, space->iterations + space->elasticIterations,
			constraints, maxConstraints, (ke < 1e-10f ? 0.0f : ke)
			);

	drawString(0, 220, buffer);
}

static void
reshape(int width, int height)
{
	glViewport(0, 0, width, height);

	float rx = width / 2.0f;
	float ry = height / 2.0f;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrthof(-rx, rx, -ry, ry, -1.0f, 1.0f);
	glTranslatef(0.5f, 0.5f, 0.0f);
}

static void
display(void)
{
	cpVect newPoint = cpvlerp(mousePoint_last, mousePoint, 0.25f);
	mouseBody->p = newPoint;
	mouseBody->v = cpvmult(cpvsub(newPoint, mousePoint_last), 60.0f);
	mousePoint_last = newPoint;
	currDemo->updateFunc(ticks);

//	glClear(GL_COLOR_BUFFER_BIT);
//
//	drawSpace(space, currDemo->drawOptions ? currDemo->drawOptions : &options);
//	drawInstructions();
//	drawInfo();
//	drawString(-300, -210, messageString);
//
//	glutSwapBuffers();
	ticks++;
}

static char *
demoTitle(chipmunkDemo *demo)
{
	static char title[1024];
	sprintf(title, "Demo: %s", demo->name);

	return title;
}

static void
runDemo(chipmunkDemo *demo)
{
	if(currDemo)
		currDemo->destroyFunc();

	currDemo = demo;
	ticks = 0;
	mouseJoint = NULL;
	messageString[0] = '\0';
	maxArbiters = 0;
	maxPoints = 0;
	maxConstraints = 0;
	space = currDemo->initFunc();

//	glutSetWindowTitle(demoTitle(currDemo));
}

static void
keyboard(unsigned char key, int x, int y)
{
	int index = key - 'a';

	if(0 <= index && index < demoCount){
		runDemo(demos[index]);
	} else if(key == '\r'){
		runDemo(currDemo);
	} else if(key == '-'){
		options.drawHash = !options.drawHash;
	} else if(key == '='){
		options.drawBBs = !options.drawBBs;
	} else if(key == '\\'){
		glEnable(GL_LINE_SMOOTH);
		glEnable(GL_POINT_SMOOTH);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
		glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
	}
}

static cpVect
mouseToSpace(int x, int y)
{
//	GLdouble model[16];
//	glGetDoublev(GL_MODELVIEW_MATRIX, model);
//
//	GLdouble proj[16];
//	glGetDoublev(GL_PROJECTION_MATRIX, proj);
//
//	GLint view[4];
//	glGetIntegerv(GL_VIEWPORT, view);
//
//	GLdouble mx, my, mz;
//	gluUnProject(x, glutGet(GLUT_WINDOW_HEIGHT) - y, 0.0f, model, proj, view, &mx, &my, &mz);
//
//	return cpv(mx, my);

	return cpv(x,y);
}

static void
mouse(int x, int y)
{
	mousePoint = mouseToSpace(x, y);
}

static void
click(int button, int state, int x, int y)
{
//	if(button == GLUT_LEFT_BUTTON){
//		if(state == GLUT_DOWN){
//			cpVect point = mouseToSpace(x, y);
//
//			cpShape *shape = cpSpacePointQueryFirst(space, point, GRABABLE_MASK_BIT, CP_NO_GROUP);
//			if(shape){
//				cpBody *body = shape->body;
//				mouseJoint = cpPivotJointNew2(mouseBody, body, cpvzero, cpBodyWorld2Local(body, point));
//				mouseJoint->maxForce = 50000.0f;
//				mouseJoint->biasCoef = 0.15f;
//				cpSpaceAddConstraint(space, mouseJoint);
//			}
//		} else if(mouseJoint){
//			cpSpaceRemoveConstraint(space, mouseJoint);
//			cpConstraintFree(mouseJoint);
//			mouseJoint = NULL;
//		}
//	}
}

static void
timercall(int value)
{
//	glutTimerFunc(SLEEP_TICKS, timercall, 0);
//
//	glutPostRedisplay();
}

static void
set_arrowDirection()
{
	int x = 0, y = 0;

	if(key_up) y += 1;
	if(key_down) y -= 1;
	if(key_right) x += 1;
	if(key_left) x -= 1;

	arrowDirection = cpv(x, y);
}

static void
arrowKeyDownFunc(int key, int x, int y)
{
//	if(key == GLUT_KEY_UP) key_up = 1;
//	else if(key == GLUT_KEY_DOWN) key_down = 1;
//	else if(key == GLUT_KEY_LEFT) key_left = 1;
//	else if(key == GLUT_KEY_RIGHT) key_right = 1;

	set_arrowDirection();
}

static void
arrowKeyUpFunc(int key, int x, int y)
{
//	if(key == GLUT_KEY_UP) key_up = 0;
//	else if(key == GLUT_KEY_DOWN) key_down = 0;
//	else if(key == GLUT_KEY_LEFT) key_left = 0;
//	else if(key == GLUT_KEY_RIGHT) key_right = 0;

	set_arrowDirection();
}

//static void
//idle(void)
//{
//	glutPostRedisplay();
//}

static void
initGL(void)
{
	glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

	glEnableClientState(GL_VERTEX_ARRAY);
}

static void
glutStuff(int argc, const char *argv[])
{
//	glutInit(&argc, (char**)argv);
//
//	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
//
//	glutInitWindowSize(640, 480);
//	glutCreateWindow(demoTitle(demos[firstDemoIndex]));
//
//	initGL();
//
//	glutReshapeFunc(reshape);
//	glutDisplayFunc(display);
//	//	glutIdleFunc(idle);
//	glutTimerFunc(SLEEP_TICKS, timercall, 0);
//
//	glutIgnoreKeyRepeat(1);
//	glutKeyboardFunc(keyboard);
//
//	glutSpecialFunc(arrowKeyDownFunc);
//	glutSpecialUpFunc(arrowKeyUpFunc);
//
//	glutMotionFunc(mouse);
//	glutPassiveMotionFunc(mouse);
//	glutMouseFunc(click);
}

//#include <sys/time.h>
//void time_trial(char index, int count)
//{
//	currDemo = demos[index];
//	space = currDemo->initFunc();
//
//	struct timeval start_time, end_time;
//	gettimeofday(&start_time, NULL);
//
//	for(int i=0; i<count; i++)
//		currDemo->updateFunc(i);
//
//	gettimeofday(&end_time, NULL);
//	long millisecs = (end_time.tv_sec - start_time.tv_sec)*1000;
//	millisecs += (end_time.tv_usec - start_time.tv_usec)/1000;
//
//	currDemo->destroyFunc();
//
//	printf("Time(%c) = %ldms\n", index + 'a', millisecs);
//}

void ChipmunkTestScene::runThisTest()
{
    // create layer
    ChipmunkTestLayer* pLayer = new ChipmunkTestLayer();
	pLayer->init();
    pLayer->autorelease();

    addChild(pLayer);

    CCDirector::sharedDirector()->replaceScene(this);
}

void ChipmunkTestLayer::init()
{
    CCLayer::init();
    CCLayer::setIsTouchEnabled(true);

	demoIndex = 0;

    cpInitChipmunk();
	cp_collision_slop = 0.2f;
    mouseBody = cpBodyNew(INFINITY, INFINITY);

    runDemo(demos[firstDemoIndex]);

    label = CCLabelTTF::labelWithString(demos[firstDemoIndex]->name, "Arial", 32);
    label->setPosition( ccp(0, -300) );
    label->setColor(ccBLACK);
    addChild(label);

    // [self schedule: @selector(step:)];
    scheduleUpdate();
}

void ChipmunkTestLayer::onEnter()
{
    CCLayer::onEnter();

    glClearColor(1,1,1,1);
    float factor = 1.0f;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_WOPHONE)
	// portraint
    //glOrthof(-320/factor, 320/factor, -480/factor, 480/factor, -1.0f, 1.0f);
	// landscape
    glOrthof(-320/factor, 320/factor, 0/factor, 960/factor, 1.0f, -1.0f);
#else
    // portraint
    //glOrthof(-320/factor, 320/factor, -480/factor, 480/factor, -1.0f, 1.0f);
    // landscape
    glOrthof(-480/factor, 480/factor, -320/factor, 320/factor, 1.0f, -1.0f);
#endif

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glPointSize(3.0f);
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
    glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
    glLineWidth(1.5f);
}

void ChipmunkTestLayer::onExit()
{
    CCDirector::sharedDirector()->setGLDefaultValues();

    CCLayer::onExit();
}

void ChipmunkTestLayer::update(ccTime dt)
{
    // call chipmunk demo c function
    display();
}

void ChipmunkTestLayer::draw()
{
    drawSpace(space, currDemo->drawOptions ? currDemo->drawOptions : &options);
}

void ChipmunkTestLayer::ccTouchesEnded(CCSet* touches, CCEvent *event)
{
    demoIndex++;
    if( demoIndex >= maxDemos )
        demoIndex = 0;

    runDemo(demos[demoIndex]);

    label->setString( demos[demoIndex]->name );
}


code:
/* Copyright (c) 2007 Scott Lembcke
 *
 * 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 "chipmunk.h"
#include "drawSpace.h"
#include "../testBasic.h"

struct chipmunkDemo;

typedef cpSpace *(*demoInitFunc)(void);
typedef void (*demoUpdateFunc)(int ticks);
typedef void (*demoDestroyFunc)(void);

typedef struct chipmunkDemo {
	char *name;

	drawSpaceOptions *drawOptions;

	demoInitFunc initFunc;
	demoUpdateFunc updateFunc;
	demoDestroyFunc destroyFunc;
} chipmunkDemo;

static inline cpFloat
frand(void)
{
	return (cpFloat)rand()/(cpFloat)RAND_MAX;
}

extern cpVect arrowDirection;
extern char messageString[1024];

#define GRABABLE_MASK_BIT (1<<31)
#define NOT_GRABABLE_MASK (~GRABABLE_MASK_BIT)

// cocos2d-x test interface decalre
class ChipmunkTestScene : public TestScene
{
public:
    virtual void runThisTest();
};

class ChipmunkTestLayer : public CCLayer
{
protected:
	std::string	m_strTitle;
    int demoIndex;
    CCLabelTTF *label;

public:
    void init();
	// virtual std::string title();
	virtual void onEnter();
    virtual void onExit();
    void update(ccTime dt);
    void draw();
    void ccTouchesEnded(CCSet* touches, CCEvent *event);

	// void restartCallback(CCObject* pSender);
	// void nextCallback(CCObject* pSender);
	// void backCallback(CCObject* pSender);
};


code:
/* Copyright (c) 2007 Scott Lembcke
 *
 * 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 "cocos2d.h"
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <string.h>
#include "chipmunk.h"
#include "drawSpace.h"

using namespace cocos2d;

/*
	IMPORTANT - READ ME!

	This file sets up a simple interface that the individual demos can use to get
	a Chipmunk space running and draw what's in it. In order to keep the Chipmunk
	examples clean and simple, they contain no graphics code. All drawing is done
	by accessing the Chipmunk structures at a very low level. It is NOT
	recommended to write a game or application this way as it does not scale
	beyond simple shape drawing and is very dependent on implementation details
	about Chipmunk which may change with little to no warning.
*/

#define LINE_COLOR 0.0f, 0.0f, 0.0f, 1.0f
#define COLLISION_COLOR 1.0f, 0.0f, 0.0f, 1.0f
#define BODY_COLOR 0.0f, 0.0f, 1.0f, 1.0f

static void
glColor_from_pointer(void *ptr)
{
	unsigned long val = (long)ptr;

	// hash the pointer up nicely
	val = (val+0x7ed55d16) + (val<<12);
	val = (val^0xc761c23c) ^ (val>>19);
	val = (val+0x165667b1) + (val<<5);
	val = (val+0xd3a2646c) ^ (val<<9);
	val = (val+0xfd7046c5) + (val<<3);
	val = (val^0xb55a4f09) ^ (val>>16);

//	GLfloat v = (GLfloat)val/(GLfloat)ULONG_MAX;
//	v = 0.95f - v*0.15f;
//
//	glColor3f(v, v, v);

	GLubyte r = (val>>0) & 0xFF;
	GLubyte g = (val>>8) & 0xFF;
	GLubyte b = (val>>16) & 0xFF;

	GLubyte max = r>g ? (r>b ? r : b) : (g>b ? g : b);

	const int mult = 127;
	const int add = 63;
	r = (r*mult)/max + add;
	g = (g*mult)/max + add;
	b = (b*mult)/max + add;

	// glColor4ub isn't implemented on some android devices
	// glColor4ub(r, g, b, 255);
	glColor4f( ((GLfloat)r)/255, ((GLfloat)g) / 255, ((GLfloat)b)/255, 1.0f );
}

static void
glColor_for_shape(cpShape *shape, cpSpace *space)
{
	cpBody *body = shape->body;
	if(body){
		if(body->node.next){
			GLfloat v = 0.25f;
			glColor4f(v,v,v,1);
			return;
		} else if(body->node.idleTime > space->sleepTimeThreshold) {
			GLfloat v = 0.9f;
			glColor4f(v,v,v,1);
			return;
		}
	}

	glColor_from_pointer(shape);
}

static const GLfloat circleVAR[] = {
	 0.0000f,  1.0000f,
	 0.2588f,  0.9659f,
	 0.5000f,  0.8660f,
	 0.7071f,  0.7071f,
	 0.8660f,  0.5000f,
	 0.9659f,  0.2588f,
	 1.0000f,  0.0000f,
	 0.9659f, -0.2588f,
	 0.8660f, -0.5000f,
	 0.7071f, -0.7071f,
	 0.5000f, -0.8660f,
	 0.2588f, -0.9659f,
	 0.0000f, -1.0000f,
	-0.2588f, -0.9659f,
	-0.5000f, -0.8660f,
	-0.7071f, -0.7071f,
	-0.8660f, -0.5000f,
	-0.9659f, -0.2588f,
	-1.0000f, -0.0000f,
	-0.9659f,  0.2588f,
	-0.8660f,  0.5000f,
	-0.7071f,  0.7071f,
	-0.5000f,  0.8660f,
	-0.2588f,  0.9659f,
	 0.0000f,  1.0000f,
	 0.0f, 0.0f, // For an extra line to see the rotation.
};
static const int circleVAR_count = sizeof(circleVAR)/sizeof(GLfloat)/2;

static void
drawCircleShape(cpBody *body, cpCircleShape *circle, cpSpace *space)
{
	glVertexPointer(2, GL_FLOAT, 0, circleVAR);

	// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
	// Needed states:  GL_VERTEX_ARRAY,
	// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
	glDisable(GL_TEXTURE_2D);
	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);

	glPushMatrix(); {
		cpVect center = circle->tc;
		glTranslatef(center.x, center.y, 0.0f);
		glRotatef(body->a*180.0f/(float)M_PI, 0.0f, 0.0f, 1.0f);
		glScalef(circle->r, circle->r, 1.0f);

		if(!circle->shape.sensor){
			glColor_for_shape((cpShape *)circle, space);
			glDrawArrays(GL_TRIANGLE_FAN, 0, circleVAR_count - 1);
		}

		glColor4f(LINE_COLOR);
		glDrawArrays(GL_LINE_STRIP, 0, circleVAR_count);
	} glPopMatrix();

	// restore default GL state
	glEnable(GL_TEXTURE_2D);
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

static const GLfloat pillVAR[] = {
	 0.0000f,  1.0000f, 1.0f,
	 0.2588f,  0.9659f, 1.0f,
	 0.5000f,  0.8660f, 1.0f,
	 0.7071f,  0.7071f, 1.0f,
	 0.8660f,  0.5000f, 1.0f,
	 0.9659f,  0.2588f, 1.0f,
	 1.0000f,  0.0000f, 1.0f,
	 0.9659f, -0.2588f, 1.0f,
	 0.8660f, -0.5000f, 1.0f,
	 0.7071f, -0.7071f, 1.0f,
	 0.5000f, -0.8660f, 1.0f,
	 0.2588f, -0.9659f, 1.0f,
	 0.0000f, -1.0000f, 1.0f,

	 0.0000f, -1.0000f, 0.0f,
	-0.2588f, -0.9659f, 0.0f,
	-0.5000f, -0.8660f, 0.0f,
	-0.7071f, -0.7071f, 0.0f,
	-0.8660f, -0.5000f, 0.0f,
	-0.9659f, -0.2588f, 0.0f,
	-1.0000f, -0.0000f, 0.0f,
	-0.9659f,  0.2588f, 0.0f,
	-0.8660f,  0.5000f, 0.0f,
	-0.7071f,  0.7071f, 0.0f,
	-0.5000f,  0.8660f, 0.0f,
	-0.2588f,  0.9659f, 0.0f,
	 0.0000f,  1.0000f, 0.0f,
};
static const int pillVAR_count = sizeof(pillVAR)/sizeof(GLfloat)/3;

static void
drawSegmentShape(cpBody *body, cpSegmentShape *seg, cpSpace *space)
{
	cpVect a = seg->ta;
	cpVect b = seg->tb;

	if(seg->r){
		glVertexPointer(3, GL_FLOAT, 0, pillVAR);

		// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
		// Needed states:  GL_VERTEX_ARRAY,
		// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
		glDisable(GL_TEXTURE_2D);
		glDisableClientState(GL_COLOR_ARRAY);
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);

		glPushMatrix(); {
			cpVect d = cpvsub(b, a);
			cpVect r = cpvmult(d, seg->r/cpvlength(d));

			const GLfloat matrix[] = {
				 r.x, r.y, 0.0f, 0.0f,
				-r.y, r.x, 0.0f, 0.0f,
				 d.x, d.y, 0.0f, 0.0f,
				 a.x, a.y, 0.0f, 1.0f,
			};
			glMultMatrixf(matrix);

			if(!seg->shape.sensor){
				glColor_for_shape((cpShape *)seg, space);
				glDrawArrays(GL_TRIANGLE_FAN, 0, pillVAR_count);
			}

			glColor4f(LINE_COLOR);
			glDrawArrays(GL_LINE_LOOP, 0, pillVAR_count);
		} glPopMatrix();

		// restore default GL state
		glEnable(GL_TEXTURE_2D);
		glEnableClientState(GL_COLOR_ARRAY);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);

	} else {
		glColor4f(LINE_COLOR);
		ccDrawLine(ccp(a.x, a.y),ccp(b.x, b.y));
	}
}

static void
drawPolyShape(cpBody *body, cpPolyShape *poly, cpSpace *space)
{
	int count = poly->numVerts;
#if CP_USE_DOUBLES
	glVertexPointer(2, GL_DOUBLE, 0, poly->tVerts);
#else
	glVertexPointer(2, GL_FLOAT, 0, poly->tVerts);
#endif

	// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
	// Needed states:  GL_VERTEX_ARRAY,
	// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
	glDisable(GL_TEXTURE_2D);
	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);

	if(!poly->shape.sensor){
		glColor_for_shape((cpShape *)poly, space);
		glDrawArrays(GL_TRIANGLE_FAN, 0, count);
	}

	glColor4f(LINE_COLOR);
	glDrawArrays(GL_LINE_LOOP, 0, count);

	// restore default GL state
	glEnable(GL_TEXTURE_2D);
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

static void
drawObject(cpShape *shape, cpSpace *space)
{
	cpBody *body = shape->body;

	switch(shape->klass->type){
		case CP_CIRCLE_SHAPE:
			drawCircleShape(body, (cpCircleShape *)shape, space);
			break;
		case CP_SEGMENT_SHAPE:
			drawSegmentShape(body, (cpSegmentShape *)shape, space);
			break;
		case CP_POLY_SHAPE:
			drawPolyShape(body, (cpPolyShape *)shape, space);
			break;
		default:
			CCLOG("Bad enumeration in drawObject().\n");
            break;
	}
}

static const GLfloat springVAR[] = {
	0.00f, 0.0f,
	0.20f, 0.0f,
	0.25f, 3.0f,
	0.30f,-6.0f,
	0.35f, 6.0f,
	0.40f,-6.0f,
	0.45f, 6.0f,
	0.50f,-6.0f,
	0.55f, 6.0f,
	0.60f,-6.0f,
	0.65f, 6.0f,
	0.70f,-3.0f,
	0.75f, 6.0f,
	0.80f, 0.0f,
	1.00f, 0.0f,
};
static const int springVAR_count = sizeof(springVAR)/sizeof(GLfloat)/2;

static void
drawSpring(cpDampedSpring *spring, cpBody *body_a, cpBody *body_b)
{
	cpVect a = cpvadd(body_a->p, cpvrotate(spring->anchr1, body_a->rot));
	cpVect b = cpvadd(body_b->p, cpvrotate(spring->anchr2, body_b->rot));

	glPointSize(5.0f);
	ccDrawPoint( ccp(a.x, a.y) );
	ccDrawPoint( ccp(b.x, b.y) );

	cpVect delta = cpvsub(b, a);

	// Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
	// Needed states:  GL_VERTEX_ARRAY,
	// Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
	glDisable(GL_TEXTURE_2D);
	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);

	glVertexPointer(2, GL_FLOAT, 0, springVAR);
	glPushMatrix(); {
		GLfloat x = a.x;
		GLfloat y = a.y;
		GLfloat cos = delta.x;
		GLfloat sin = delta.y;
		GLfloat s = 1.0f/cpvlength(delta);

		const GLfloat matrix[] = {
				 cos,    sin, 0.0f, 0.0f,
			-sin*s,  cos*s, 0.0f, 0.0f,
				0.0f,   0.0f, 1.0f, 0.0f,
					 x,      y, 0.0f, 1.0f,
		};

		glMultMatrixf(matrix);
		glDrawArrays(GL_LINE_STRIP, 0, springVAR_count);
	} glPopMatrix();

	// restore default GL state
	glEnable(GL_TEXTURE_2D);
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);

}

static void
drawConstraint(cpConstraint *constraint)
{
	cpBody *body_a = constraint->a;
	cpBody *body_b = constraint->b;

	const cpConstraintClass *klass = constraint->klass;
	if(klass == cpPinJointGetClass()){
		cpPinJoint *joint = (cpPinJoint *)constraint;

		cpVect a = cpvadd(body_a->p, cpvrotate(joint->anchr1, body_a->rot));
		cpVect b = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot));

		glPointSize(5.0f);
		ccDrawPoint( ccp(a.x, a.y) );
		ccDrawPoint( ccp(b.x, b.y) );
		ccDrawLine( ccp(a.x, a.y), ccp(b.x, b.y) );

	} else if(klass == cpSlideJointGetClass()){
		cpSlideJoint *joint = (cpSlideJoint *)constraint;

		cpVect a = cpvadd(body_a->p, cpvrotate(joint->anchr1, body_a->rot));
		cpVect b = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot));

		glPointSize(5.0f);
		ccDrawPoint( ccp(a.x, a.y) );
		ccDrawPoint( ccp(b.x, b.y) );
		ccDrawLine( ccp(a.x, a.y), ccp(b.x, b.y) );

	} else if(klass == cpPivotJointGetClass()){
		cpPivotJoint *joint = (cpPivotJoint *)constraint;

		cpVect a = cpvadd(body_a->p, cpvrotate(joint->anchr1, body_a->rot));
		cpVect b = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot));

		glPointSize(10.0f);
		ccDrawPoint( ccp(a.x, a.y) );
		ccDrawPoint( ccp(b.x, b.y) );
	} else if(klass == cpGrooveJointGetClass()){
		cpGrooveJoint *joint = (cpGrooveJoint *)constraint;

		cpVect a = cpvadd(body_a->p, cpvrotate(joint->grv_a, body_a->rot));
		cpVect b = cpvadd(body_a->p, cpvrotate(joint->grv_b, body_a->rot));
		cpVect c = cpvadd(body_b->p, cpvrotate(joint->anchr2, body_b->rot));

		glPointSize(5.0f);
		ccDrawPoint( ccp(c.x, c.y) );
		ccDrawLine( ccp(a.x, a.y), ccp(b.x, b.y) );
	} else if(klass == cpDampedSpringGetClass()){
		drawSpring((cpDampedSpring *)constraint, body_a, body_b);
	} else {
//		printf("Cannot draw constraint\n");
	}
}

static void
drawBB(cpShape *shape, void *unused)
{
	CCPoint vertices[] = {
		ccp(shape->bb.l, shape->bb.b),
		ccp(shape->bb.l, shape->bb.t),
		ccp(shape->bb.r, shape->bb.t),
		ccp(shape->bb.r, shape->bb.b),
	};
	ccDrawPoly(vertices, 4, false);

}

// copied from cpSpaceHash.c
static inline cpHashValue
hash_func(cpHashValue x, cpHashValue y, cpHashValue n)
{
	return (x*1640531513ul ^ y*2654435789ul) % n;
}

static void
drawSpatialHash(cpSpaceHash *hash)
{
	cpBB bb = cpBBNew(-320, -240, 320, 240);

	cpFloat dim = hash->celldim;
	int n = hash->numcells;

	int l = (int)floor(bb.l/dim);
	int r = (int)floor(bb.r/dim);
	int b = (int)floor(bb.b/dim);
	int t = (int)floor(bb.t/dim);

	for(int i=l; i<=r; i++){
		for(int j=b; j<=t; j++){
			int cell_count = 0;

			int index = hash_func(i,j,n);
			for(cpSpaceHashBin *bin = hash->table[index]; bin; bin = bin->next)
				cell_count++;

			GLfloat v = 1.0f - (GLfloat)cell_count/10.0f;
			glColor4f(v,v,v,1);
//			glRectf(i*dim, j*dim, (i + 1)*dim, (j + 1)*dim);
		}
	}
}

void
drawSpace(cpSpace *space, drawSpaceOptions *options)
{
	if(options->drawHash){
		glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE);
		drawSpatialHash(space->activeShapes);
		glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
		drawSpatialHash(space->staticShapes);
		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
	}

	glLineWidth(options->lineThickness);
	if(options->drawShapes){
		cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)drawObject, space);
		cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)drawObject, space);
	}

	glLineWidth(1.0f);
	if(options->drawBBs){
		glColor4f(0.3f, 0.5f, 0.3f,1);
		cpSpaceHashEach(space->activeShapes, (cpSpaceHashIterator)drawBB, NULL);
		cpSpaceHashEach(space->staticShapes, (cpSpaceHashIterator)drawBB, NULL);
	}

	cpArray *constraints = space->constraints;

	glColor4f(0.5f, 1.0f, 0.5f, 1);
	for(int i=0, count = constraints->num; i<count; i++){
		drawConstraint((cpConstraint *)constraints->arr[i]);
	}

	if(options->bodyPointSize){
		glPointSize(options->bodyPointSize);

		cpArray *bodies = space->bodies;

		glColor4f(LINE_COLOR);
		for(int i=0, count = bodies->num; i<count; i++){
			cpBody *body = (cpBody *)bodies->arr[i];
			ccDrawPoint( ccp(body->p.x, body->p.y) );
		}

//			glColor3f(0.5f, 0.5f, 0.5f);
//			cpArray *components = space->components;
//			for(int i=0; i<components->num; i++){
//				cpBody *root = components->arr[i];
//				cpBody *body = root, *next;
//				do {
//					next = body->node.next;
//					glVertex2f(body->p.x, body->p.y);
//				} while((body = next) != root);
//			}
	}

	if(options->collisionPointSize){
		glPointSize(options->collisionPointSize);
		cpArray *arbiters = space->arbiters;
		for(int i=0; i<arbiters->num; i++){
			cpArbiter *arb = (cpArbiter*)arbiters->arr[i];

			glColor4f(COLLISION_COLOR);
			for(int i=0; i<arb->numContacts; i++){
				cpVect v = arb->contacts[i].p;
				ccDrawPoint( ccp(v.x, v.y) );
			}
		}
	}
}


code:
/* Copyright (c) 2007 Scott Lembcke
 *
 * 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 _DRAW_SPACE_H_
#define _DRAW_SPACE_H_

typedef struct drawSpaceOptions {
	int drawHash;
	int drawBBs;
	int drawShapes;
	float collisionPointSize;
	float bodyPointSize;
	float lineThickness;
} drawSpaceOptions;

void drawSpace(cpSpace *space, drawSpaceOptions *options);

#endif //_DRAW_SPACE_H_


code:
#include "ClickAndMoveTest.h"
#include "../testResource.h"

enum
{
	kTagSprite = 1,
};

void ClickAndMoveTestScene::runThisTest()
{
    CCLayer* pLayer = new MainLayer();
    pLayer->autorelease();

    addChild(pLayer);
    CCDirector::sharedDirector()->replaceScene(this);
}

MainLayer::MainLayer()
{
	setIsTouchEnabled(true);

	CCSprite* sprite = CCSprite::spriteWithFile(s_pPathGrossini);

	CCLayer* layer = CCLayerColor::layerWithColor(ccc4f(255,255,0,255));
	addChild(layer, -1);

	addChild(sprite, 0, kTagSprite);
	sprite->setPosition( CCPointMake(20,150) );

	sprite->runAction( CCJumpTo::actionWithDuration(4, CCPointMake(300,48), 100, 4) );

	layer->runAction( CCRepeatForever::actionWithAction(
														(CCActionInterval*)( CCSequence::actions(
																			CCFadeIn::actionWithDuration(1),
																			CCFadeOut::actionWithDuration(1),
																			NULL) )
														) );
}

void MainLayer::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
{
    CCSetIterator it = pTouches->begin();
	CCTouch* touch = (CCTouch*)(*it);

	CCPoint location = touch->locationInView();
	CCPoint convertedLocation = CCDirector::sharedDirector()->convertToGL(location);

	CCNode* s = getChildByTag(kTagSprite);
	s->stopAllActions();
	s->runAction( CCMoveTo::actionWithDuration(1, CCPointMake(convertedLocation.x, convertedLocation.y) ) );
	float o = convertedLocation.x - s->getPosition().x;
	float a = convertedLocation.y - s->getPosition().y;
	float at = (float) CC_RADIANS_TO_DEGREES( atanf( o/a) );

	if( a < 0 )
	{
		if(  o < 0 )
			at = 180 + fabs(at);
		else
			at = 180 - fabs(at);
	}

	s->runAction( CCRotateTo::actionWithDuration(1, at) );
}


code:
#ifndef _CLICK_AND_MOVE_TEST_H_
#define _CLICK_AND_MOVE_TEST_H_

#include "../testBasic.h"

class ClickAndMoveTestScene : public TestScene
{
public:
    virtual void runThisTest();
};

class MainLayer : public CCLayer
{
public:
	MainLayer();
	virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent);
};

#endif


code:
#include "CocosDenshionTest.h"
#include "cocos2d.h"
#include "SimpleAudioEngine.h"

// android effect only support ogg
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
	#define EFFECT_FILE		"effect2.ogg"
#elif( CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE)
	#define EFFECT_FILE		"effect1.raw"
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_QT)
    #define EFFECT_FILE		"effect2.ogg"
#else
	#define EFFECT_FILE		"effect1.wav"
#endif // CC_PLATFORM_ANDROID

#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
	#define MUSIC_FILE		"music.mid"
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_QNX)
	#define MUSIC_FILE		"background.ogg"
#elif (CC_TARGET_PLATFORM == CC_PLATFORM_QT)
    #define MUSIC_FILE		"background.ogg"
#else
	#define MUSIC_FILE		"background.mp3"
#endif // CC_PLATFORM_WIN32

using namespace cocos2d;
using namespace CocosDenshion;

#define LINE_SPACE          40

CocosDenshionTest::CocosDenshionTest()
: m_pItmeMenu(NULL),
m_tBeginPos(CCPointZero),
m_nSoundId(0)
{
	std::string testItems[] = {
		"play background music",
		"stop background music",
		"pause background music",
		"resume background music",
		"rewind background music",
		"is background music playing",
		"play effect",
        "play effect repeatly",
		"stop effect",
		"unload effect",
		"add background music volume",
		"sub background music volume",
		"add effects volume",
		"sub effects volume",
		"pause effect",
		"resume effect",
		"pause all effects",
		"resume all effects",
		"stop all effects"
	};

	// add menu items for tests
	m_pItmeMenu = CCMenu::menuWithItems(NULL);
	CCSize s = CCDirector::sharedDirector()->getWinSize();
	m_nTestCount = sizeof(testItems) / sizeof(testItems[0]);

	for (int i = 0; i < m_nTestCount; ++i)
	{
//#if (CC_TARGET_PLATFORM == CC_PLATFORM_MARMALADE)
//		CCLabelBMFont* label = CCLabelBMFont::labelWithString(testItems[i].c_str(),  "fonts/arial16.fnt");
//#else
        CCLabelTTF* label = CCLabelTTF::labelWithString(testItems[i].c_str(), "Arial", 24);
//#endif
        CCMenuItemLabel* pMenuItem = CCMenuItemLabel::itemWithLabel(label, this, menu_selector(CocosDenshionTest::menuCallback));

		m_pItmeMenu->addChild(pMenuItem, i + 10000);
		pMenuItem->setPosition( CCPointMake( s.width / 2, (s.height - (i + 1) * LINE_SPACE) ));
	}

	m_pItmeMenu->setContentSize(CCSizeMake(s.width, (m_nTestCount + 1) * LINE_SPACE));
	m_pItmeMenu->setPosition(CCPointZero);
	addChild(m_pItmeMenu);

	setIsTouchEnabled(true);

	// preload background music and effect
	SimpleAudioEngine::sharedEngine()->preloadBackgroundMusic( CCFileUtils::fullPathFromRelativePath(MUSIC_FILE) );
	SimpleAudioEngine::sharedEngine()->preloadEffect( CCFileUtils::fullPathFromRelativePath(EFFECT_FILE) );

    // set default volume
    SimpleAudioEngine::sharedEngine()->setEffectsVolume(0.5);
    SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(0.5);
}

CocosDenshionTest::~CocosDenshionTest()
{
}

void CocosDenshionTest::onExit()
{
	CCLayer::onExit();

	SimpleAudioEngine::sharedEngine()->end();
}

void CocosDenshionTest::menuCallback(CCObject * pSender)
{
	// get the userdata, it's the index of the menu item clicked
	CCMenuItem* pMenuItem = (CCMenuItem *)(pSender);
	int nIdx = pMenuItem->getZOrder() - 10000;

	switch(nIdx)
	{
	// play background music
	case 0:

		SimpleAudioEngine::sharedEngine()->playBackgroundMusic(std::string(CCFileUtils::fullPathFromRelativePath(MUSIC_FILE)).c_str(), true);
		break;
	// stop background music
	case 1:
		SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();
		break;
	// pause background music
	case 2:
		SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();
		break;
	// resume background music
	case 3:
		SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();
		break;
	// rewind background music
	case 4:
		SimpleAudioEngine::sharedEngine()->rewindBackgroundMusic();
		break;
	// is background music playing
	case 5:
		if (SimpleAudioEngine::sharedEngine()->isBackgroundMusicPlaying())
		{
			CCLOG("background music is playing");
		}
		else
		{
            CCLOG("background music is not playing");
		}
		break;
	// play effect
	case 6:
		m_nSoundId = SimpleAudioEngine::sharedEngine()->playEffect(std::string(CCFileUtils::fullPathFromRelativePath(EFFECT_FILE)).c_str());
		break;
    // play effect
    case 7:
        m_nSoundId = SimpleAudioEngine::sharedEngine()->playEffect(std::string(CCFileUtils::fullPathFromRelativePath(EFFECT_FILE)).c_str(), true);
        break;
    // stop effect
	case 8:
		SimpleAudioEngine::sharedEngine()->stopEffect(m_nSoundId);
		break;
	// unload effect
	case 9:
		SimpleAudioEngine::sharedEngine()->unloadEffect(std::string(CCFileUtils::fullPathFromRelativePath(EFFECT_FILE)).c_str());
		break;
		// add bakcground music volume
	case 10:
		SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(SimpleAudioEngine::sharedEngine()->getBackgroundMusicVolume() + 0.1f);
		break;
		// sub backgroud music volume
	case 11:
		SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(SimpleAudioEngine::sharedEngine()->getBackgroundMusicVolume() - 0.1f);
		break;
		// add effects volume
	case 12:
		SimpleAudioEngine::sharedEngine()->setEffectsVolume(SimpleAudioEngine::sharedEngine()->getEffectsVolume() + 0.1f);
		break;
		// sub effects volume
	case 13:
		SimpleAudioEngine::sharedEngine()->setEffectsVolume(SimpleAudioEngine::sharedEngine()->getEffectsVolume() - 0.1f);
		break;
	case 14:
		SimpleAudioEngine::sharedEngine()->pauseEffect(m_nSoundId);
		break;
	case 15:
		SimpleAudioEngine::sharedEngine()->resumeEffect(m_nSoundId);
		break;
	case 16:
		SimpleAudioEngine::sharedEngine()->pauseAllEffects();
		break;
	case 17:
		SimpleAudioEngine::sharedEngine()->resumeAllEffects();
		break;
	case 18:
		SimpleAudioEngine::sharedEngine()->stopAllEffects();
		break;
	}

}

void CocosDenshionTest::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent)
{
	CCSetIterator it = pTouches->begin();
	CCTouch* touch = (CCTouch*)(*it);

	m_tBeginPos = touch->locationInView();
	m_tBeginPos = CCDirector::sharedDirector()->convertToGL( m_tBeginPos );
}

void CocosDenshionTest::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent)
{
	CCSetIterator it = pTouches->begin();
	CCTouch* touch = (CCTouch*)(*it);

	CCPoint touchLocation = touch->locationInView();
	touchLocation = CCDirector::sharedDirector()->convertToGL( touchLocation );
	float nMoveY = touchLocation.y - m_tBeginPos.y;

	CCPoint curPos  = m_pItmeMenu->getPosition();
	CCPoint nextPos = ccp(curPos.x, curPos.y + nMoveY);
	CCSize winSize = CCDirector::sharedDirector()->getWinSize();
	if (nextPos.y < 0.0f)
	{
		m_pItmeMenu->setPosition(CCPointZero);
		return;
	}

	if (nextPos.y > ((m_nTestCount + 1)* LINE_SPACE - winSize.height))
	{
		m_pItmeMenu->setPosition(ccp(0, ((m_nTestCount + 1)* LINE_SPACE - winSize.height)));
		return;
	}

	m_pItmeMenu->setPosition(nextPos);
	m_tBeginPos = touchLocation;
}

void CocosDenshionTestScene::runThisTest()
{
	CCLayer* pLayer = new CocosDenshionTest();
	addChild(pLayer);
	pLayer->autorelease();

	CCDirector::sharedDirector()->replaceScene(this);
}


code:
#ifndef __COCOS_DENSHION_TEST__
#define __COCOS_DENSHION_TEST__

#include "../testBasic.h"

class CocosDenshionTest : public CCLayer
{
public:
	CocosDenshionTest(void);
	~CocosDenshionTest(void);

	void menuCallback(CCObject * pSender);
	virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent);
	virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);
	virtual void onExit();

private:
	CCMenu* m_pItmeMenu;
	CCPoint m_tBeginPos;
	int m_nTestCount;
	unsigned int m_nSoundId;
};

class CocosDenshionTestScene : public TestScene
{
public:
	virtual void runThisTest();
};

#endif //__COCOS_DENSHION_TEST__


code:
#include "CocosNodeTest.h"
#include "../testResource.h"

enum
{
	kTagSprite1 = 1,
	kTagSprite2 = 2,
	kTagSprite3 = 3,
	kTagSlider,
};

CCLayer* nextCocosNodeAction();
CCLayer* backCocosNodeAction();
CCLayer* restartCocosNodeAction();

//------------------------------------------------------------------
//
// TestCocosNodeDemo
//
//------------------------------------------------------------------

static int sceneIdx = -1;

#define MAX_LAYER	12

CCLayer* createCocosNodeLayer(int nIndex)
{
	switch(nIndex)
	{
		case 0: return new CameraCenterTest();
		case 1: return new Test2();
		case 2: return new Test4();
		case 3: return new Test5();
		case 4: return new Test6();
		case 5: return new StressTest1();
		case 6: return new StressTest2();
		case 7: return new NodeToWorld();
		case 8: return new SchedulerTest1();
		case 9: return new CameraOrbitTest();
		case 10: return new CameraZoomTest();
		case 11: return new ConvertToNode();
	}

	return NULL;
}

CCLayer* nextCocosNodeAction()
{
	sceneIdx++;
	sceneIdx = sceneIdx % MAX_LAYER;

	CCLayer* pLayer = createCocosNodeLayer(sceneIdx);
	pLayer->autorelease();

	return pLayer;
}

CCLayer* backCocosNodeAction()
{
	sceneIdx--;
	int total = MAX_LAYER;
	if( sceneIdx < 0 )
		sceneIdx += total;

	CCLayer* pLayer = createCocosNodeLayer(sceneIdx);
	pLayer->autorelease();

	return pLayer;
}

CCLayer* restartCocosNodeAction()
{
	CCLayer* pLayer = createCocosNodeLayer(sceneIdx);
	pLayer->autorelease();

	return pLayer;
}

TestCocosNodeDemo::TestCocosNodeDemo(void)
{
}

TestCocosNodeDemo::~TestCocosNodeDemo(void)
{
}

std::string TestCocosNodeDemo::title()
{
	return "No title";
}

std::string TestCocosNodeDemo::subtitle()
{
	return "";
}

void TestCocosNodeDemo::onEnter()
{
	CCLayer::onEnter();

	CCSize s = CCDirector::sharedDirector()->getWinSize();

	CCLabelTTF* label = CCLabelTTF::labelWithString(title().c_str(), "Arial", 32);
	addChild(label, 1);
	label->setPosition( CCPointMake(s.width/2, s.height-50) );

	std::string strSubtitle = subtitle();
	if( ! strSubtitle.empty() )
	{
		CCLabelTTF* l = CCLabelTTF::labelWithString(strSubtitle.c_str(), "Thonburi", 16);
		addChild(l, 1);
		l->setPosition( CCPointMake(s.width/2, s.height-80) );
	}

	CCMenuItemImage *item1 = CCMenuItemImage::itemFromNormalImage(s_pPathB1, s_pPathB2, this, menu_selector(TestCocosNodeDemo::backCallback) );
	CCMenuItemImage *item2 = CCMenuItemImage::itemFromNormalImage(s_pPathR1,s_pPathR2, this, menu_selector(TestCocosNodeDemo::restartCallback) );
	CCMenuItemImage *item3 = CCMenuItemImage::itemFromNormalImage(s_pPathF1, s_pPathF2, this, menu_selector(TestCocosNodeDemo::nextCallback) );

	CCMenu *menu = CCMenu::menuWithItems(item1, item2, item3, NULL);

	menu->setPosition( CCPointZero );
	item1->setPosition( CCPointMake( s.width/2 - 100,30) );
	item2->setPosition( CCPointMake( s.width/2, 30) );
	item3->setPosition( CCPointMake( s.width/2 + 100,30) );

	addChild(menu, 1);
}

void TestCocosNodeDemo::restartCallback(CCObject* pSender)
{
	CCScene* s = new CocosNodeTestScene();//CCScene::node();
	s->addChild(restartCocosNodeAction());

	CCDirector::sharedDirector()->replaceScene(s);
    s->release();
}

void TestCocosNodeDemo::nextCallback(CCObject* pSender)
{
	CCScene* s = new CocosNodeTestScene();//CCScene::node();
	s->addChild( nextCocosNodeAction() );
	CCDirector::sharedDirector()->replaceScene(s);
    s->release();
}

void TestCocosNodeDemo::backCallback(CCObject* pSender)
{
	CCScene* s = new CocosNodeTestScene();//CCScene::node();
	s->addChild( backCocosNodeAction() );
	CCDirector::sharedDirector()->replaceScene(s);
    s->release();
}

//------------------------------------------------------------------
//
// Test2
//
//------------------------------------------------------------------
void Test2::onEnter()
{
	TestCocosNodeDemo::onEnter();

	CCSize s = CCDirector::sharedDirector()->getWinSize();

	CCSprite *sp1 = CCSprite::spriteWithFile(s_pPathSister1);
	CCSprite *sp2 = CCSprite::spriteWithFile(s_pPathSister2);
	CCSprite *sp3 = CCSprite::spriteWithFile(s_pPathSister1);
	CCSprite *sp4 = CCSprite::spriteWithFile(s_pPathSister2);

	sp1->setPosition(CCPointMake(100, s.height /2 ));
	sp2->setPosition(CCPointMake(380, s.height /2 ));
	addChild(sp1);
	addChild(sp2);

	sp3->setScale(0.25f);
	sp4->setScale(0.25f);

	sp1->addChild(sp3);
	sp2->addChild(sp4);

	CCActionInterval* a1 = CCRotateBy::actionWithDuration(2, 360);
	CCActionInterval* a2 = CCScaleBy::actionWithDuration(2, 2);

	CCAction* action1 = CCRepeatForever::actionWithAction(
													(CCActionInterval*)(CCSequence::actions(a1, a2, a2->reverse(), NULL))
												);
	CCAction* action2 = CCRepeatForever::actionWithAction(
													(CCActionInterval*)(CCSequence::actions(
																						(CCActionInterval*)(a1->copy()->autorelease()),
																						(CCActionInterval*)(a2->copy()->autorelease()),
																						a2->reverse(),
																						NULL) )
												);

	sp2->setAnchorPoint(CCPointMake(0,0));

	sp1->runAction(action1);
	sp2->runAction(action2);
}

std::string Test2::title()
{
	return "anchorPoint and children";
}

//------------------------------------------------------------------
//
// Test4
//
//------------------------------------------------------------------
#define SID_DELAY2		1
#define SID_DELAY4		2

Test4::Test4()
{
	CCSprite *sp1 = CCSprite::spriteWithFile(s_pPathSister1);
	CCSprite *sp2 = CCSprite::spriteWithFile(s_pPathSister2);

	sp1->setPosition( CCPointMake(100,160) );
	sp2->setPosition( CCPointMake(380,160) );

	addChild(sp1, 0, 2);
	addChild(sp2, 0, 3);

	schedule( schedule_selector(Test4::delay2), 2.0f);
	schedule( schedule_selector(Test4::delay4), 4.0f);
}

void Test4::delay2(ccTime dt)
{
	CCSprite* node = (CCSprite*)(getChildByTag(2));
	CCAction* action1 = CCRotateBy::actionWithDuration(1, 360);
	node->runAction(action1);
}

void Test4::delay4(ccTime dt)
{
	unschedule(schedule_selector(Test4::delay4));
	removeChildByTag(3, false);
}

std::string Test4::title()
{
	return "tags";
}

//------------------------------------------------------------------
//
// Test5
//
//------------------------------------------------------------------
Test5::Test5()
{
	CCSprite* sp1 = CCSprite::spriteWithFile(s_pPathSister1);
	CCSprite* sp2 = CCSprite::spriteWithFile(s_pPathSister2);

	sp1->setPosition(CCPointMake(100,160));
	sp2->setPosition(CCPointMake(380,160));

	CCRotateBy* rot = CCRotateBy::actionWithDuration(2, 360);
	CCActionInterval* rot_back = rot->reverse();
    CCAction* forever1 = CCRepeatForever::actionWithAction(
    //CCAction* forever = CCRepeatForever::actionWithAction(
													(CCActionInterval*)(CCSequence::actions(rot, rot_back, NULL))
												);
    CCAction* forever2 = (CCAction*)(forever1->copy()->autorelease());
    forever1->setTag(101);
	forever2->setTag(102);

	addChild(sp1, 0, kTagSprite1);
	addChild(sp2, 0, kTagSprite2);

    //sp1->runAction(forever);
    sp1->runAction(forever1);
	sp2->runAction(forever2);

	schedule( schedule_selector(Test5::addAndRemove), 2.0f);
}

void Test5::addAndRemove(ccTime dt)
{
	CCNode* sp1 = getChildByTag(kTagSprite1);
	CCNode* sp2 = getChildByTag(kTagSprite2);

	sp1->retain();
	sp2->retain();

	removeChild(sp1, false);
	removeChild(sp2, true);

	addChild(sp1, 0, kTagSprite1);
	addChild(sp2, 0, kTagSprite2);

	sp1->release();
	sp2->release();
}

std::string Test5::title()
{
	return "remove and cleanup";
}

//------------------------------------------------------------------
//
// Test6
//
//------------------------------------------------------------------
Test6::Test6()
{
	CCSprite* sp1 = CCSprite::spriteWithFile(s_pPathSister1);
	CCSprite* sp11 = CCSprite::spriteWithFile(s_pPathSister1);

	CCSprite* sp2 = CCSprite::spriteWithFile(s_pPathSister2);
	CCSprite* sp21 = CCSprite::spriteWithFile(s_pPathSister2);

	sp1->setPosition(CCPointMake(100,160));
	sp2->setPosition(CCPointMake(380,160));

	CCActionInterval* rot = CCRotateBy::actionWithDuration(2, 360);
	CCActionInterval* rot_back = rot->reverse();
	CCAction* forever1 = CCRepeatForever::actionWithAction(
															(CCActionInterval*)(CCSequence::actions(rot, rot_back, NULL)));
	CCAction* forever11 =  (CCAction*)(forever1->copy()->autorelease());

	CCAction* forever2 =  (CCAction*)(forever1->copy()->autorelease());
	CCAction* forever21 =  (CCAction*)(forever1->copy()->autorelease());

	addChild(sp1, 0, kTagSprite1);
	sp1->addChild(sp11);
	addChild(sp2, 0, kTagSprite2);
	sp2->addChild(sp21);

	sp1->runAction(forever1);
	sp11->runAction(forever11);
	sp2->runAction(forever2);
	sp21->runAction(forever21);

	schedule( schedule_selector(Test6::addAndRemove), 2.0f);
}

void Test6::addAndRemove(ccTime dt)
{
	CCNode* sp1 = getChildByTag(kTagSprite1);
	CCNode* sp2 = getChildByTag(kTagSprite2);

	sp1->retain();
	sp2->retain();

	removeChild(sp1, false);
	removeChild(sp2, true);

	addChild(sp1, 0, kTagSprite1);
	addChild(sp2, 0, kTagSprite2);

	sp1->release();
	sp2->release();

}

std::string Test6::title()
{
	return "remove/cleanup with children";
}

//------------------------------------------------------------------
//
// StressTest1
//
//------------------------------------------------------------------
StressTest1::StressTest1()
{
	CCSize s = CCDirector::sharedDirector()->getWinSize();

	CCSprite *sp1 = CCSprite::spriteWithFile(s_pPathSister1);
	addChild(sp1, 0, kTagSprite1);

	sp1->setPosition( CCPointMake(s.width/2, s.height/2) );

	schedule( schedule_selector(StressTest1::shouldNotCrash), 1.0f);
}

void StressTest1::shouldNotCrash(ccTime dt)
{
	unschedule(schedule_selector(StressTest1::shouldNotCrash));

	CCSize s = CCDirector::sharedDirector()->getWinSize();

	// if the node has timers, it crashes
	CCNode* explosion = CCParticleSun::node();
	((CCParticleSun*)explosion)->setTexture(CCTextureCache::sharedTextureCache()->addImage("Images/fire.png"));

	// if it doesn't, it works Ok.
//	CocosNode *explosion = [Sprite spriteWithFile:@"grossinis_sister2.png");

	explosion->setPosition( CCPointMake(s.width/2, s.height/2) );

	runAction( CCSequence::actions(
							CCRotateBy::actionWithDuration(2, 360),
							CCCallFuncN::actionWithTarget(this, callfuncN_selector(StressTest1::removeMe)),
							NULL) );

	addChild(explosion);
}

// remove
void StressTest1::removeMe(CCNode* node)
{
	m_pParent->removeChild(node, true);
	nextCallback(this);
}

std::string StressTest1::title()
{
	return "stress test #1: no crashes";
}

//------------------------------------------------------------------
//
// StressTest2
//
//------------------------------------------------------------------
StressTest2::StressTest2()
{
	CCSize s = CCDirector::sharedDirector()->getWinSize();

	CCLayer* sublayer = CCLayer::node();

	CCSprite *sp1 = CCSprite::spriteWithFile(s_pPathSister1);
	sp1->setPosition( CCPointMake(80, s.height/2) );

	CCActionInterval* move = CCMoveBy::actionWithDuration(3, CCPointMake(350,0));
	CCActionInterval* move_ease_inout3 = CCEaseInOut::actionWithAction((CCActionInterval*)(move->copy()->autorelease()), 2.0f);
	CCActionInterval* move_ease_inout_back3 = move_ease_inout3->reverse();
	CCFiniteTimeAction* seq3 = CCSequence::actions( move_ease_inout3, move_ease_inout_back3, NULL);
	sp1->runAction( CCRepeatForever::actionWithAction((CCActionInterval*)seq3) );
	sublayer->addChild(sp1, 1);

	CCParticleFire* fire = CCParticleFire::node();
	fire->setTexture(CCTextureCache::sharedTextureCache()->addImage("Images/fire.png"));
	fire->setPosition( CCPointMake(80, s.height/2-50) );

	CCActionInterval* copy_seq3 = (CCActionInterval*)(seq3->copy()->autorelease());

	fire->runAction( CCRepeatForever::actionWithAction(copy_seq3) );
	sublayer->addChild(fire, 2);

	schedule(schedule_selector(StressTest2::shouldNotLeak), 6.0f);

	addChild(sublayer, 0, kTagSprite1);
}

void StressTest2::shouldNotLeak(ccTime dt)
{
	unschedule( schedule_selector(StressTest2::shouldNotLeak) );
	CCLayer* sublayer = (CCLayer*)getChildByTag(kTagSprite1);
	sublayer->removeAllChildrenWithCleanup(true);
}

std::string StressTest2::title()
{
	return "stress test #2: no leaks";
}

//------------------------------------------------------------------
//
// SchedulerTest1
//
//------------------------------------------------------------------
SchedulerTest1::SchedulerTest1()
{
	CCLayer*layer = CCLayer::node();
	//UXLOG("retain count after init is %d", layer->retainCount());                // 1

	addChild(layer, 0);
	//UXLOG("retain count after addChild is %d", layer->retainCount());      // 2

	layer->schedule( schedule_selector(SchedulerTest1::doSomething) );
	//UXLOG("retain count after schedule is %d", layer->retainCount());      // 3 : (object-c viersion), but win32 version is still 2, because CCTimer class don't save target.

	layer->unschedule(schedule_selector(SchedulerTest1::doSomething));
	//UXLOG("retain count after unschedule is %d", layer->retainCount());		// STILL 3!  (win32 is '2')
}

void SchedulerTest1::doSomething(ccTime dt)
{

}

std::string SchedulerTest1::title()
{
	return "cocosnode scheduler test #1";
}

//------------------------------------------------------------------
//
// NodeToWorld
//
//------------------------------------------------------------------
NodeToWorld::NodeToWorld()
{
	//
	// This code tests that nodeToParent works OK:
	//  - It tests different anchor Points
	//  - It tests different children anchor points

	CCSprite *back = CCSprite::spriteWithFile(s_back3);
	addChild( back, -10);
	back->setAnchorPoint( CCPointMake(0,0) );
	CCSize backSize = back->getContentSize();

	CCMenuItem *item = CCMenuItemImage::itemFromNormalImage(s_PlayNormal, s_PlaySelect);
	CCMenu *menu = CCMenu::menuWithItems(item, NULL);
	menu->alignItemsVertically();
	menu->setPosition( CCPointMake(backSize.width/2, backSize.height/2));
	back->addChild(menu);

	CCActionInterval* rot = CCRotateBy::actionWithDuration(5, 360);
	CCAction* fe = CCRepeatForever::actionWithAction( rot);
	item->runAction( fe );

	CCActionInterval* move = CCMoveBy::actionWithDuration(3, CCPointMake(200,0));
	CCActionInterval* move_back = move->reverse();
	CCFiniteTimeAction* seq = CCSequence::actions( move, move_back, NULL);
	CCAction* fe2 = CCRepeatForever::actionWithAction((CCActionInterval*)seq);
	back->runAction(fe2);
}

std::string NodeToWorld::title()
{
	return "nodeToParent transform";
}

//------------------------------------------------------------------
//
// CameraOrbitTest
//
//------------------------------------------------------------------
void CameraOrbitTest::onEnter()
{
	TestCocosNodeDemo::onEnter();
	CCDirector::sharedDirector()->setProjection(kCCDirectorProjection3D);
}

void CameraOrbitTest::onExit()
{
	CCDirector::sharedDirector()->setProjection(kCCDirectorProjection2D);
	TestCocosNodeDemo::onExit();
}

CameraOrbitTest::CameraOrbitTest()
{
	CCSize s = CCDirector::sharedDirector()->getWinSize();

	CCSprite *p = CCSprite::spriteWithFile(s_back3);
	addChild( p, 0);
	p->setPosition( CCPointMake(s.width/2, s.height/2) );
	p->setOpacity( 128 );

	CCSprite* sprite;
	CCOrbitCamera* orbit;
	CCCamera* cam;
	CCSize ss;

	// LEFT
    s = p->getContentSize();
	sprite = CCSprite::spriteWithFile(s_pPathGrossini);
	sprite->setScale(0.5f);
	p->addChild(sprite, 0);
	sprite->setPosition( CCPointMake(s.width/4*1, s.height/2) );
	cam = sprite->getCamera();
	orbit = CCOrbitCamera::actionWithDuration(2, 1, 0, 0, 360, 0, 0);
	sprite->runAction( CCRepeatForever::actionWithAction( orbit ) );

	// CENTER
	sprite = CCSprite::spriteWithFile(s_pPathGrossini);
	sprite->setScale( 1.0f );
	p->addChild(sprite, 0);
	sprite->setPosition( CCPointMake(s.width/4*2, s.height/2) );
	orbit = CCOrbitCamera::actionWithDuration(2, 1, 0, 0, 360, 45, 0);
	sprite->runAction( CCRepeatForever::actionWithAction( orbit ) );

	// RIGHT
	sprite = CCSprite::spriteWithFile(s_pPathGrossini);
	sprite->setScale( 2.0f );
	p->addChild(sprite, 0);
	sprite->setPosition( CCPointMake(s.width/4*3, s.height/2) );
	ss = sprite->getContentSize();
	orbit = CCOrbitCamera::actionWithDuration(2, 1, 0, 0, 360, 90, -45),
	sprite->runAction( CCRepeatForever::actionWithAction(orbit) );

	// PARENT
	orbit = CCOrbitCamera::actionWithDuration(10, 1, 0, 0, 360, 0, 90);
	p->runAction( CCRepeatForever::actionWithAction( orbit ) );

	setScale( 1 );
}

std::string CameraOrbitTest::title()
{
	return "Camera Orbit test";
}

//------------------------------------------------------------------
//
// CameraZoomTest
//
//------------------------------------------------------------------

void CameraZoomTest::onEnter()
{
	TestCocosNodeDemo::onEnter();

	CCDirector::sharedDirector()->setProjection(kCCDirectorProjection3D);
}

void CameraZoomTest::onExit()
{
	CCDirector::sharedDirector()->setProjection(kCCDirectorProjection2D);
	TestCocosNodeDemo::onExit();
}

CameraZoomTest::CameraZoomTest()
{
	CCSize s = CCDirector::sharedDirector()->getWinSize();

	CCSprite *sprite;
	CCCamera *cam;

	// LEFT
	sprite = CCSprite::spriteWithFile(s_pPathGrossini);
	addChild( sprite, 0);
	sprite->setPosition( CCPointMake(s.width/4*1, s.height/2) );
	cam = sprite->getCamera();
	cam->setEyeXYZ(0, 0, 415);

	// CENTER
	sprite = CCSprite::spriteWithFile(s_pPathGrossini);
	addChild( sprite, 0, 40);
	sprite->setPosition(CCPointMake(s.width/4*2, s.height/2));
//		cam = [sprite camera);
//		[cam setEyeX:0 eyeY:0 eyeZ:415/2);

	// RIGHT
	sprite = CCSprite::spriteWithFile(s_pPathGrossini);
	addChild( sprite, 0, 20);
	sprite->setPosition(CCPointMake(s.width/4*3, s.height/2));
//		cam = [sprite camera);
//		[cam setEyeX:0 eyeY:0 eyeZ:-485);
//		[cam setCenterX:0 centerY:0 centerZ:0);

	m_z = 0;
	scheduleUpdate();
}

void CameraZoomTest::update(ccTime dt)
{
	CCNode *sprite;
	CCCamera *cam;

	m_z += dt * 100;

	sprite = getChildByTag(20);
	cam = sprite->getCamera();
	cam->setEyeXYZ(0, 0, m_z);

	sprite = getChildByTag(40);
	cam = sprite->getCamera();
	cam->setEyeXYZ(0, 0, m_z);
}

std::string CameraZoomTest::title()
{
	return "Camera Zoom test";
}

//------------------------------------------------------------------
//
// CameraCenterTest
//
//------------------------------------------------------------------
CameraCenterTest::CameraCenterTest()
{
	CCSize s = CCDirector::sharedDirector()->getWinSize();

	CCSprite *sprite;
	CCOrbitCamera *orbit;

	// LEFT-TOP
	sprite = new CCSprite();//::node();
    sprite->init();
	addChild( sprite, 0);
	sprite->setPosition(CCPointMake(s.width/5*1, s.height/5*1));
	sprite->setColor(ccRED);
	sprite->setTextureRect(CCRectMake(0, 0, 120, 50));
	orbit = CCOrbitCamera::actionWithDuration(10, 1, 0, 0, 360, 0, 0);
	sprite->runAction(CCRepeatForever::actionWithAction( orbit ));
    sprite->release();
//		[sprite setAnchorPoint: CCPointMake(0,1));

	// LEFT-BOTTOM
	sprite = new CCSprite();//::node();
    sprite->init();
	addChild( sprite, 0, 40);
	sprite->setPosition(CCPointMake(s.width/5*1, s.height/5*4));
	sprite->setColor(ccBLUE);
	sprite->setTextureRect(CCRectMake(0, 0, 120, 50));
	orbit = CCOrbitCamera::actionWithDuration(10, 1, 0, 0, 360, 0, 0);
	sprite->runAction(CCRepeatForever::actionWithAction( orbit ));
    sprite->release();
    //		[sprite setAnchorPoint: CCPointMake(0,0));

	// RIGHT-TOP
	sprite = new CCSprite();//::node();
    sprite->init();
	addChild( sprite, 0);
	sprite->setPosition(CCPointMake(s.width/5*4, s.height/5*1));
	sprite->setColor(ccYELLOW);
	sprite->setTextureRect(CCRectMake(0, 0, 120, 50));
	orbit = CCOrbitCamera::actionWithDuration(10, 1, 0, 0, 360, 0, 0);
	sprite->runAction(CCRepeatForever::actionWithAction( orbit) );
    sprite->release();
//		[sprite setAnchorPoint: CCPointMake(1,1));

	// RIGHT-BOTTOM
	sprite = new CCSprite();//::node();
    sprite->init();
	addChild( sprite, 0, 40);
	sprite->setPosition(CCPointMake(s.width/5*4, s.height/5*4));
	sprite->setColor(ccGREEN);
	sprite->setTextureRect(CCRectMake(0, 0, 120, 50));
	orbit = CCOrbitCamera::actionWithDuration(10, 1, 0, 0, 360, 0, 0);
	sprite->runAction( CCRepeatForever::actionWithAction( orbit ) );
    sprite->release();
//		[sprite setAnchorPoint: CCPointMake(1,0));

	// CENTER
	sprite = new CCSprite();
    sprite->init();
	addChild( sprite, 0, 40);
	sprite->setPosition(CCPointMake(s.width/2, s.height/2));
	sprite->setColor(ccWHITE);
	sprite->setTextureRect(CCRectMake(0, 0, 120, 50));
	orbit = CCOrbitCamera::actionWithDuration(10, 1, 0, 0, 360, 0, 0);
	sprite->runAction(CCRepeatForever::actionWithAction( orbit ) );
    sprite->release();
//		[sprite setAnchorPoint: CCPointMake(0.5f, 0.5f));
}

std::string CameraCenterTest::title()
{
	return "Camera Center test";
}

std::string CameraCenterTest::subtitle()
{
	return "Sprites should rotate at the same speed";
}

//------------------------------------------------------------------
//
// ConvertToNode
//
//------------------------------------------------------------------
ConvertToNode::ConvertToNode()
{
    setIsTouchEnabled(true);
    CCSize s = CCDirector::sharedDirector()->getWinSize();

    CCRotateBy* rotate = CCRotateBy::actionWithDuration(10, 360);
    CCRepeatForever* action = CCRepeatForever::actionWithAction(rotate);
    for(int i = 0; i < 3; i++)
    {
        CCSprite *sprite = CCSprite::spriteWithFile("Images/grossini.png");
        sprite->setPosition(ccp( s.width/4*(i+1), s.height/2));

        CCSprite *point = CCSprite::spriteWithFile("Images/r1.png");
        point->setScale(0.25f);
        point->setPosition(sprite->getPosition());
        addChild(point, 10, 100 + i);

        switch(i)
        {
        case 0:
            sprite->setAnchorPoint(CCPointZero);
            break;
        case 1:
            sprite->setAnchorPoint(ccp(0.5f, 0.5f));
            break;
        case 2:
            sprite->setAnchorPoint(ccp(1,1));
            break;
        }

        point->setPosition(sprite->getPosition());

        CCRepeatForever* copy = (CCRepeatForever*) action->copy();
        copy->autorelease();
        sprite->runAction(copy);
        addChild(sprite, i);
    }
}

void ConvertToNode::ccTouchesEnded(CCSet* touches, CCEvent *event)
{
    for( CCSetIterator it = touches->begin(); it != touches->end(); ++it)
    {
        CCTouch* touch = (CCTouch*)(*it);
        CCPoint location = touch->locationInView();

        location = CCDirector::sharedDirector()->convertToGL(location);

        for( int i = 0; i < 3; i++)
        {
            CCNode *node = getChildByTag(100+i);
            CCPoint p1, p2;

            p1 = node->convertToNodeSpaceAR(location);
            p2 = node->convertToNodeSpace(location);

            CCLOG("AR: x=%.2f, y=%.2f -- Not AR: x=%.2f, y=%.2f", p1.x, p1.y, p2.x, p2.y);
        }
    }
}

std::string ConvertToNode::title()
{
    return "Convert To Node Space";
}

std::string ConvertToNode::subtitle()
{
    return "testing convertToNodeSpace / AR. Touch and see console";
}

void CocosNodeTestScene::runThisTest()
{
    CCLayer* pLayer = nextCocosNodeAction();
    addChild(pLayer);

    CCDirector::sharedDirector()->replaceScene(this);
}


code:
#ifndef _COCOSNODE_TEST_H_
#define _COCOSNODE_TEST_H_

////----#include "cocos2d.h"
#include "../testBasic.h"

class TestCocosNodeDemo : public CCLayer
{
public:
	TestCocosNodeDemo(void);
	~TestCocosNodeDemo(void);

	virtual std::string title();
	virtual std::string subtitle();
	virtual void onEnter();

	void restartCallback(CCObject* pSender);
	void nextCallback(CCObject* pSender);
	void backCallback(CCObject* pSender);
};

class Test2 : public TestCocosNodeDemo
{
public:
	virtual void onEnter();
	virtual std::string title();
};

class Test4 : public TestCocosNodeDemo
{
public:
	Test4();
	void delay2(ccTime dt);
	void delay4(ccTime dt);

	virtual std::string title();
};

class Test5 : public TestCocosNodeDemo
{
public:
	Test5();
	void addAndRemove(ccTime dt);

	virtual std::string title();
};

class Test6 : public TestCocosNodeDemo
{
public:
	Test6();
	void addAndRemove(ccTime dt);

	virtual std::string title();
};

class StressTest1 : public TestCocosNodeDemo
{
	void shouldNotCrash(ccTime dt);
	void removeMe(CCNode* node);
public:
	StressTest1();

	virtual std::string title();
};

class StressTest2 : public TestCocosNodeDemo
{
	void shouldNotLeak(ccTime dt);
public:
	StressTest2();

	virtual std::string title();
};

class SchedulerTest1 : public TestCocosNodeDemo
{
public:
	SchedulerTest1();
	void doSomething(ccTime dt);

	virtual std::string title();
};

class NodeToWorld : public TestCocosNodeDemo
{
public:
	NodeToWorld();
	virtual std::string title();
};

class CameraOrbitTest : public TestCocosNodeDemo
{
public:
	CameraOrbitTest();

	virtual void onEnter();
	virtual void onExit();
	virtual std::string title();
};

class CameraZoomTest : public TestCocosNodeDemo
{
	float	m_z;
public:
	CameraZoomTest();
	void update(ccTime dt);

	virtual void onEnter();
	virtual void onExit();

	virtual std::string title();
};

class CameraCenterTest : public TestCocosNodeDemo
{
public:
	CameraCenterTest();
	virtual std::string title();
	virtual std::string subtitle();
};

class ConvertToNode : public TestCocosNodeDemo
{
public:
    ConvertToNode();
    virtual void ccTouchesEnded(CCSet* touches, CCEvent *event);
    virtual std::string title();
    virtual std::string subtitle();
};

class CocosNodeTestScene : public TestScene
{
public:
    virtual void runThisTest();
};

//CCLayer* nextAction();

#endif


code:
#include "CurlTest.h"
#include "stdio.h"
#include "stdlib.h"
#include "curl/curl.h"

CurlTest::CurlTest()
{
	CCSize s = CCDirector::sharedDirector()->getWinSize();
	CCLabelTTF* label = CCLabelTTF::labelWithString("Curl Test", "Arial", 28);
	addChild(label, 0);
	label->setPosition( ccp(s.width/2, s.height-50) );

    setIsTouchEnabled(true);

    // create a label to display the tip string
    m_pLabel = CCLabelTTF::labelWithString("Touch the screen to connect", "Arial", 22);
    m_pLabel->setPosition(ccp(s.width / 2, s.height / 2));
	addChild(m_pLabel, 0);

    m_pLabel->retain();
}

// the test code is
// http://curl.haxx.se/mail/lib-2009-12/0071.html
void CurlTest::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent)
{
	CURL *curl;
	CURLcode res;
	char buffer[10];

	curl = curl_easy_init();
	if (curl)
	{
		curl_easy_setopt(curl, CURLOPT_URL, "google.com");
		res = curl_easy_perform(curl);
		/* always cleanup */
		curl_easy_cleanup(curl);
		if (res == 0)
		{
			m_pLabel->setString("0 response");
		}
		else
		{
			sprintf(buffer,"code: %i",res);
			m_pLabel->setString(buffer);
		}
	}
	else
	{
		m_pLabel->setString("no curl");
	}
}

CurlTest::~CurlTest()
{
	m_pLabel->release();
}

void CurlTestScene::runThisTest()
{
    CCLayer* pLayer = new CurlTest();
    addChild(pLayer);

    CCDirector::sharedDirector()->replaceScene(this);
    pLayer->release();
}


code:
#ifndef _CURL_TEST_H_
#define _CURL_TEST_H_

#include "cocos2d.h"
#include "../testBasic.h"

class CurlTest : public CCLayer
{
public:
	CurlTest();
	~CurlTest();

	virtual void ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent);

private:
	cocos2d::CCLabelTTF*         m_pLabel;
};

class CurlTestScene : public TestScene
{
public:
    virtual void runThisTest();
};

#endif // _CURL_TEST_H_


code:
#include "CurrentLanguageTest.h"

CurrentLanguageTest::CurrentLanguageTest()
{
	CCSize s = CCDirector::sharedDirector()->getWinSize();
	CCLabelTTF* label = CCLabelTTF::labelWithString("Current language Test", "Arial", 28);
	addChild(label, 0);
	label->setPosition( ccp(s.width/2, s.height-50) );

	CCLabelTTF *labelLanguage = CCLabelTTF::labelWithString("", "Arial", 20);
	labelLanguage->setPosition(ccp(s.width/2, s.height/2));

	ccLanguageType currentLanguageType = CCApplication::sharedApplication().getCurrentLanguage();
	switch (currentLanguageType)
	{
	case kLanguageEnglish:
		labelLanguage->setString("current language is English");
		break;
	case kLanguageChinese:
		labelLanguage->setString("current language is Chinese");
		break;
    case kLanguageFrench:
        labelLanguage->setString("current language is French");
        break;
    case kLanguageGerman:
        labelLanguage->setString("current language is German");
        break;
    case kLanguageItalian:
        labelLanguage->setString("current language is Italian");
        break;
    case kLanguageRussian:
        labelLanguage->setString("current language is Russian");
        break;
    case kLanguageSpanish:
        labelLanguage->setString("current language is Spanish");
        break;
	}

	addChild(labelLanguage);
}

void CurrentLanguageTestScene::runThisTest()
{
    CCLayer* pLayer = new CurrentLanguageTest();
    addChild(pLayer);

    CCDirector::sharedDirector()->replaceScene(this);
    pLayer->release();
}


code:
#ifndef _CURRENT_LANGUAGE_TEST_H_
#define _CURRENT_LANGUAGE_TEST_H_

#include "cocos2d.h"
#include "../testBasic.h"

class CurrentLanguageTest : public CCLayer
{
public:
	CurrentLanguageTest();
};

class CurrentLanguageTestScene : public TestScene
{
public:
    virtual void runThisTest();
};

#endif // _CURRENT_LANGUAGE_TEST_H_


code:
#include "DirectorTest.h"
#include "../testResource.h"

#define MAX_LAYER	1

CCLayer* nextDirectorTestCase();
CCLayer* backDirectorTestCase();
CCLayer* restartDirectorTestCase();

static int sceneIdx=-1;
static ccDeviceOrientation s_currentOrientation = CCDeviceOrientationPortrait;

CCLayer* createTestCaseLayer(int index)
{
    switch (index)
    {
    case 0:
        {
            Director1* pRet = new Director1();
            pRet->init();
            pRet->autorelease();
            return pRet;
        }
    default:
        return NULL;
    }
}

CCLayer* nextDirectorTestCase()
{
	sceneIdx++;
	sceneIdx = sceneIdx % MAX_LAYER;

	return createTestCaseLayer(sceneIdx);
}

CCLayer* backDirectorTestCase()
{
	sceneIdx--;
	if( sceneIdx < 0 )
		sceneIdx += MAX_LAYER;

    return createTestCaseLayer(sceneIdx);
}

CCLayer* restartDirectorTestCase()
{
    return createTestCaseLayer(sceneIdx);
}

///---------------------------------------
//
// DirectorTest
//
///---------------------------------------
bool DirectorTest::init()
{
    bool bRet = false;
    do
    {
        CC_BREAK_IF(! CCLayer::init());
        CCSize s = CCDirector::sharedDirector()->getWinSize();

        CCLabelTTF *label = CCLabelTTF::labelWithString(title().c_str(), "Arial", 26);
        addChild(label, 1);
        label->setPosition(ccp(s.width/2, s.height-50));

        std::string sSubtitle = subtitle();
        if (sSubtitle.length())
        {
            CCLabelTTF *l = CCLabelTTF::labelWithString(sSubtitle.c_str(), "Thonburi", 16);
            addChild(l, 1);
            l->setPosition(ccp(s.width/2, s.height-80));
        }

        CCMenuItemImage *item1 = CCMenuItemImage::itemFromNormalImage(s_pPathB1, s_pPathB2, this, menu_selector(DirectorTest::backCallback));
        CCMenuItemImage *item2 = CCMenuItemImage::itemFromNormalImage(s_pPathR1, s_pPathR2, this, menu_selector(DirectorTest::restartCallback));
        CCMenuItemImage *item3 = CCMenuItemImage::itemFromNormalImage(s_pPathF1, s_pPathF2, this, menu_selector(DirectorTest::nextCallback));

        CCMenu *menu = CCMenu::menuWithItems(item1, item2, item3, NULL);
        menu->setPosition(CCPointZero);
        item1->setPosition(ccp( s.width/2 - 100,30));
        item2->setPosition(ccp( s.width/2, 30));
        item3->setPosition(ccp( s.width/2 + 100,30));

        bRet = true;
    } while (0);

    return bRet;
}

void DirectorTest::restartCallback(CCObject* pSender)
{
    CCScene *s = new DirectorTestScene();
	s->addChild(restartDirectorTestCase());
    CCDirector::sharedDirector()->replaceScene(s);
    s->autorelease();
}

void DirectorTest::nextCallback(CCObject* pSender)
{
    CCScene *s = new DirectorTestScene();
    s->addChild(nextDirectorTestCase());
    CCDirector::sharedDirector()->replaceScene(s);
    s->autorelease();
}

void DirectorTest::backCallback(CCObject* pSender)
{
    CCScene *s = new DirectorTestScene();
    s->addChild(backDirectorTestCase());
    CCDirector::sharedDirector()->replaceScene(s);
    s->autorelease();
}

std::string DirectorTest::title()
{
	return "No title";
}

std::string DirectorTest::subtitle()
{
	return "";
}

///---------------------------------------
//
// Director1
//
///---------------------------------------
bool Director1::init()
{
    bool bRet = false;

    do
    {
        CC_BREAK_IF(! DirectorTest::init());

		setIsTouchEnabled(true);
        CCSize s = CCDirector::sharedDirector()->getWinSize();

        CCMenuItem *item = CCMenuItemFont::itemFromString("Rotate Device", this, menu_selector(Director1::rotateDevice));
        CCMenu *menu = CCMenu::menuWithItems(item, NULL);
		menu->setPosition(ccp( s.width/2, s.height/2));
		addChild(menu);

        bRet = true;
	} while (0);

	return bRet;
}

void Director1::newOrientation()
{
	switch (s_currentOrientation)
    {
		case CCDeviceOrientationLandscapeLeft:
			s_currentOrientation = CCDeviceOrientationPortrait;
			break;
		case CCDeviceOrientationPortrait:
			s_currentOrientation = CCDeviceOrientationLandscapeRight;
			break;
		case CCDeviceOrientationLandscapeRight:
			s_currentOrientation = CCDeviceOrientationPortraitUpsideDown;
			break;
		case CCDeviceOrientationPortraitUpsideDown:
			s_currentOrientation = CCDeviceOrientationLandscapeLeft;
			break;
	}
    CCDirector::sharedDirector()->setDeviceOrientation(s_currentOrientation);
}

void Director1::rotateDevice(CCObject* pSender)
{
	newOrientation();
    restartCallback(NULL);
}

void Director1::ccTouchesEnded(CCSet * touches, CCEvent* event)
{
    CCSetIterator it;
    CCTouch* touch;

    for( it = touches->begin(); it != touches->end(); it++)
    {
        touch = (CCTouch*)(*it);

        if(!touch)
            break;
		CCPoint a = touch->locationInView();

        CCDirector *director = CCDirector::sharedDirector();
		CCPoint b = director->convertToUI(director->convertToGL(a));
		CCLog("(%d,%d) == (%d,%d)", (int) a.x, (int)a.y, (int)b.x, (int)b.y );
	}
}

std::string Director1::title()
{
	return "Testing conversion";
}

std::string Director1::subtitle()
{
	return "Tap screen and see the debug console";
}

///---------------------------------------
//
// DirectorTestScene
//
///---------------------------------------
void DirectorTestScene::runThisTest()
{
    s_currentOrientation = CCDeviceOrientationPortrait;
    CCLayer* pLayer = nextDirectorTestCase();
    addChild(pLayer);

    CCDirector::sharedDirector()->replaceScene(this);
}

void DirectorTestScene::MainMenuCallback(CCObject* pSender)
{
    CCDirector::sharedDirector()->setDeviceOrientation(CCDeviceOrientationPortrait);
    TestScene::MainMenuCallback(pSender);
}


code:
#ifndef __DIRECTOR_TEST_H__
#define __DIRECTOR_TEST_H__

#include "../testBasic.h"

class DirectorTest: public CCLayer
{
public:
    virtual bool init();

    void restartCallback(CCObject* pSender);
    void nextCallback(CCObject* pSender);
    void backCallback(CCObject* pSender);

    virtual std::string title();
    virtual std::string subtitle();
};

class Director1 : public DirectorTest
{
public:
    virtual bool init();

    void newOrientation();
    void rotateDevice(CCObject* pSender);
    void ccTouchesEnded(CCSet * touches, CCEvent* event);

    virtual std::string title();
    virtual std::string subtitle();
};

class DirectorTestScene : public TestScene
{
public:
    virtual void runThisTest();

    virtual void MainMenuCallback(CCObject* pSender);
};

#endif


code:
#include "DrawPrimitivesTest.h"

DrawPrimitivesTest::DrawPrimitivesTest()
{
}

void DrawPrimitivesTest::draw()
{
	CCLayer::draw();

    CCSize s = CCDirector::sharedDirector()->getWinSize();

	// draw a simple line
	// The default state is:
	// Line Width: 1
	// color: 255,255,255,255 (white, non-transparent)
	// Anti-Aliased
	glEnable(GL_LINE_SMOOTH);
	ccDrawLine( CCPointMake(0, 0), CCPointMake(s.width, s.height) );

	// line: color, width, aliased
	// glLineWidth > 1 and GL_LINE_SMOOTH are not compatible
	// GL_SMOOTH_LINE_WIDTH_RANGE = (1,1) on iPhone
	glDisable(GL_LINE_SMOOTH);
	glLineWidth( 5.0f );
	/*glColor4ub(255,0,0,255);*/
	glColor4f(1.0, 0.0, 0.0, 1.0);
	ccDrawLine( CCPointMake(0, s.height), CCPointMake(s.width, 0) );

	// TIP:
	// If you are going to use always the same color or width, you don't
	// need to call it before every draw
	//
	// Remember: OpenGL is a state-machine.

	// draw big point in the center
	glPointSize(64);
	/*glColor4ub(0,0,255,128);*/
	glColor4f(0.0, 0.0, 1.0, 0.5);
	ccDrawPoint( CCPointMake(s.width / 2, s.height / 2) );

	// draw 4 small points
	CCPoint points[] = { CCPointMake(60,60), CCPointMake(70,70), CCPointMake(60,70), CCPointMake(70,60) };
	glPointSize(4);
	/*glColor4ub(0,255,255,255);*/
	glColor4f(0.0, 1.0, 1.0, 1.0);
	ccDrawPoints( points, 4);

	// draw a green circle with 10 segments
	glLineWidth(16);
	/*glColor4ub(0, 255, 0, 255);*/
	glColor4f(0.0, 1.0, 0.0, 1.0);
	ccDrawCircle( CCPointMake(s.width/2,  s.height/2), 100, 0, 10, false);

	// draw a green circle with 50 segments with line to center
	glLineWidth(2);
	/*glColor4ub(0, 255, 255, 255);*/
	glColor4f(0.0, 1.0, 1.0, 1.0);
	ccDrawCircle( CCPointMake(s.width/2, s.height/2), 50, CC_DEGREES_TO_RADIANS(90), 50, true);

	// open yellow poly
	/*glColor4ub(255, 255, 0, 255);*/
	glColor4f(1.0, 1.0, 0.0, 1.0);
	glLineWidth(10);
	CCPoint vertices[] = { CCPointMake(0,0), CCPointMake(50,50), CCPointMake(100,50), CCPointMake(100,100), CCPointMake(50,100) };
	ccDrawPoly( vertices, 5, false);

	// closed purble poly
	/*glColor4ub(255, 0, 255, 255);*/
	glColor4f(1.0, 0.0, 1.0, 1.0);
	glLineWidth(2);
	CCPoint vertices2[] = { CCPointMake(30,130), CCPointMake(30,230), CCPointMake(50,200) };
	ccDrawPoly( vertices2, 3, true);

	// draw quad bezier path
	ccDrawQuadBezier(CCPointMake(0,s.height), CCPointMake(s.width/2,s.height/2), CCPointMake(s.width,s.height), 50);

	// draw cubic bezier path
	ccDrawCubicBezier(CCPointMake(s.width/2, s.height/2), CCPointMake(s.width/2+30,s.height/2+50), CCPointMake(s.width/2+60,s.height/2-50),CCPointMake(s.width, s.height/2),100);

	// restore original values
	glLineWidth(1);
	/*glColor4ub(255,255,255,255);*/
	glColor4f(1.0, 1.0, 1.0, 1.0);
	glPointSize(1);
}

void DrawPrimitivesTestScene::runThisTest()
{
    CCLayer* pLayer = new DrawPrimitivesTest();
    addChild(pLayer);
    pLayer->release();

    CCDirector::sharedDirector()->replaceScene(this);
}


code:
#ifndef _DRAW_PRIMITIVES_TEST_H_
#define _DRAW_PRIMITIVES_TEST_H_

////----#include "cocos2d.h"
#include "../testBasic.h"

class DrawPrimitivesTest : public CCLayer
{
public:
	DrawPrimitivesTest();
	virtual void draw();
};

class DrawPrimitivesTestScene : public TestScene
{
public:
    virtual void runThisTest();
};

#endif