Mercurial > projects > chipmunkd
changeset 16:af2f61a96318
ported chipmunk demos
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/drawSpace.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,510 @@ +/* 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. + */ +module drawSpace; + +import derelict.opengl.gl; + +import chipmunkd.chipmunk; + +import std.math:PI; +import std.stdio; + +struct drawSpaceOptions { + int drawHash; + int drawBBs; + int drawShapes; + float collisionPointSize; + float bodyPointSize; + float lineThickness; +} + +/* + 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. +*/ + +enum float[3] LINE_COLOR = [0,0,0]; +enum float[3] COLLISION_COLOR = [1,0,0]; +enum float[3] BODY_COLOR = [0,0,1]; + +static void +glColor_from_pointer(void *ptr) +{ + ulong val = cast(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 = cast(ubyte)((r*mult)/max + add); + g = cast(ubyte)((g*mult)/max + add); + b = cast(ubyte)((b*mult)/max + add); + + glColor3ub(r, g, b); +} + +static void +glColor_for_shape(cpShape *shape, cpSpace *space) +{ + cpBody *_body = shape._body; + if(_body){ + if(_body.node.next){ + GLfloat v = 0.25f; + glColor3f(v,v,v); + return; + } else if(_body.node.idleTime > space.sleepTimeThreshold) { + GLfloat v = 0.9f; + glColor3f(v,v,v); + return; + } + } + + glColor_from_pointer(shape); +} + +enum 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. +]; +enum int circleVAR_count = circleVAR.length / 2; + +static void +drawCircleShape(cpBody *_body, cpCircleShape *circle, cpSpace *space) +{ + glVertexPointer(2, GL_FLOAT, 0, circleVAR.ptr); + + glPushMatrix(); { + cpVect center = circle.tc; + glTranslatef(center.x, center.y, 0.0f); + glRotatef(_body.a*180.0f/PI, 0.0f, 0.0f, 1.0f); + glScalef(circle.r, circle.r, 1.0f); + + if(!circle.shape.sensor){ + glColor_for_shape(cast(cpShape *)circle, space); + glDrawArrays(GL_TRIANGLE_FAN, 0, circleVAR_count - 1); + } + + glColor3fv(LINE_COLOR.ptr); + glDrawArrays(GL_LINE_STRIP, 0, circleVAR_count); + } glPopMatrix(); +} + +enum 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, +]; +enum int pillVAR_count = pillVAR.length/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.ptr); + glPushMatrix(); { + cpVect d = cpvsub(b, a); + cpVect r = cpvmult(d, seg.r/cpvlength(d)); + + 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.ptr); + + if(!seg.shape.sensor){ + glColor_for_shape(cast(cpShape *)seg, space); + glDrawArrays(GL_TRIANGLE_FAN, 0, pillVAR_count); + } + + glColor3fv(LINE_COLOR.ptr); + glDrawArrays(GL_LINE_LOOP, 0, pillVAR_count); + } glPopMatrix(); + } else { + glColor3fv(LINE_COLOR.ptr); + glBegin(GL_LINES); { + glVertex2f(a.x, a.y); + glVertex2f(b.x, b.y); + } glEnd(); + } +} + +static void +drawPolyShape(cpBody *_body, cpPolyShape *poly, cpSpace *space) +{ + int count = poly.numVerts; +version(CP_USE_DOUBLES) +{ + glVertexPointer(2, GL_DOUBLE, 0, poly.tVerts); +} +else +{ + glVertexPointer(2, GL_FLOAT, 0, poly.tVerts); +} + + if(!poly.shape.sensor){ + glColor_for_shape(cast(cpShape *)poly, space); + glDrawArrays(GL_TRIANGLE_FAN, 0, count); + } + + glColor3fv(LINE_COLOR.ptr); + glDrawArrays(GL_LINE_LOOP, 0, count); +} + +static void +drawObject(cpShape *shape, cpSpace *space) +{ + cpBody *_body = shape._body; + + switch(shape.klass.type){ + case cpShapeType.CP_CIRCLE_SHAPE: + drawCircleShape(_body, cast(cpCircleShape *)shape, space); + break; + case cpShapeType.CP_SEGMENT_SHAPE: + drawSegmentShape(_body, cast(cpSegmentShape *)shape, space); + break; + case cpShapeType.CP_POLY_SHAPE: + drawPolyShape(_body, cast(cpPolyShape *)shape, space); + break; + default: + writefln("Bad enumeration in drawObject()."); + } +} + +enum 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, +]; +enum int springVAR_count = springVAR.length / 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); + glBegin(GL_POINTS); { + glVertex2f(a.x, a.y); + glVertex2f(b.x, b.y); + } glEnd(); + + cpVect delta = cpvsub(b, a); + + glVertexPointer(2, GL_FLOAT, 0, springVAR.ptr); + glPushMatrix(); { + GLfloat x = a.x; + GLfloat y = a.y; + GLfloat cos = delta.x; + GLfloat sin = delta.y; + GLfloat s = 1.0f/cpvlength(delta); + + 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.ptr); + glDrawArrays(GL_LINE_STRIP, 0, springVAR_count); + } glPopMatrix(); +} + +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 = cast(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); + glBegin(GL_POINTS); { + glVertex2f(a.x, a.y); + glVertex2f(b.x, b.y); + } glEnd(); + + glBegin(GL_LINES); { + glVertex2f(a.x, a.y); + glVertex2f(b.x, b.y); + } glEnd(); + } else if(klass == cpSlideJointGetClass()){ + cpSlideJoint *joint = cast(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); + glBegin(GL_POINTS); { + glVertex2f(a.x, a.y); + glVertex2f(b.x, b.y); + } glEnd(); + + glBegin(GL_LINES); { + glVertex2f(a.x, a.y); + glVertex2f(b.x, b.y); + } glEnd(); + } else if(klass == cpPivotJointGetClass()){ + cpPivotJoint *joint = cast(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); + glBegin(GL_POINTS); { + glVertex2f(a.x, a.y); + glVertex2f(b.x, b.y); + } glEnd(); + } else if(klass == cpGrooveJointGetClass()){ + cpGrooveJoint *joint = cast(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); + glBegin(GL_POINTS); { + glVertex2f(c.x, c.y); + } glEnd(); + + glBegin(GL_LINES); { + glVertex2f(a.x, a.y); + glVertex2f(b.x, b.y); + } glEnd(); + } else if(klass == cpDampedSpringGetClass()){ + drawSpring(cast(cpDampedSpring *)constraint, body_a, body_b); + } else { +// printf("Cannot draw constraint\n"); + } +} + +static void +drawBB(cpShape *shape, void *unused) +{ + glBegin(GL_LINE_LOOP); { + glVertex2f(shape.bb.l, shape.bb.b); + glVertex2f(shape.bb.l, shape.bb.t); + glVertex2f(shape.bb.r, shape.bb.t); + glVertex2f(shape.bb.r, shape.bb.b); + } glEnd(); +} + +// copied from cpSpaceHash.c +static cpHashValue +hash_func(cpHashValue x, cpHashValue y, cpHashValue n) +{ + return cast(cpHashValue)((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 = cast(int)floorf(bb.l/dim); + int r = cast(int)floorf(bb.r/dim); + int b = cast(int)floorf(bb.b/dim); + int t = cast(int)floorf(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 - cast(GLfloat)cell_count/10.0f; + glColor3f(v,v,v); + glRectf(i*dim, j*dim, (i + 1)*dim, (j + 1)*dim); + } + } +} + +void +DrawSpace(cpSpace *space, const 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, cast(cpSpaceHashIterator)&drawObject, space); + cpSpaceHashEach(space.staticShapes, cast(cpSpaceHashIterator)&drawObject, space); + } + + glLineWidth(1.0f); + if(options.drawBBs){ + glColor3f(0.3f, 0.5f, 0.3f); + cpSpaceHashEach(space.activeShapes, cast(cpSpaceHashIterator)&drawBB, null); + cpSpaceHashEach(space.staticShapes, cast(cpSpaceHashIterator)&drawBB, null); + } + + cpArray *constraints = space.constraints; + + glColor3f(0.5f, 1.0f, 0.5f); + for(int i=0, count = constraints.num; i<count; i++){ + drawConstraint(cast(cpConstraint *)constraints.arr[i]); + } + + if(options.bodyPointSize){ + glPointSize(options.bodyPointSize); + + glBegin(GL_POINTS); { + glColor3fv(LINE_COLOR.ptr); + cpArray *bodies = space.bodies; + for(int i=0, count = bodies.num; i<count; i++){ + cpBody *_body = cast(cpBody *)bodies.arr[i]; + glVertex2f(_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); +// } + } glEnd(); + } + + if(options.collisionPointSize){ + glPointSize(options.collisionPointSize); + glBegin(GL_POINTS); { + cpArray *arbiters = space.arbiters; + for(int i=0; i<arbiters.num; i++){ + cpArbiter *arb = cast(cpArbiter*)arbiters.arr[i]; + + glColor3fv(COLLISION_COLOR.ptr); + foreach(j; 0..arb.numContacts){ + cpVect v = arb.contacts[j].p; + glVertex2f(v.x, v.y); + } + } + } glEnd(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/framework.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,93 @@ + +// written in the D programming language + +/++ + + Authors: Stephan Dilly, www.extrawurst.org + +/ + +module framework; + +import derelict.sdl.sdl; +import derelict.opengl.gl; +import derelict.opengl.glu; + +import std.string; +import std.stdio; + +void startup(string _title,int _width,int _height) +{ + DerelictGL.load(); + DerelictGLU.load(); + DerelictSDL.load(); + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) + { + throw new Exception("Failed to initialize SDL"); + } + + // Enable key repeating + if ((SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL))) + { + throw new Exception("Failed to set key repeat"); + } + + //enable to get ascii/unicode info of key event + SDL_EnableUNICODE(1); + + // Set the OpenGL attributes + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + // Set the window title + SDL_WM_SetCaption(cast(char*)toStringz(_title), null); + + int mode = SDL_OPENGL; + + // Now open a SDL OpenGL window with the given parameters + if (SDL_SetVideoMode(_width, _height, 32, mode) is null) + { + throw new Exception("Failed to open SDL window"); + } +} + +alias void delegate(int,int,bool) MouseButton; +alias void delegate(int,int) MouseMove; +alias void delegate(int,bool) KeyEvent; +public bool processEvents(KeyEvent _keyevent,MouseMove _mmove,MouseButton _mbutton) +{ + SDL_Event event; + while (SDL_PollEvent(&event)) + { + switch (event.type) + { + case SDL_KEYUP: + case SDL_KEYDOWN: + _keyevent(event.key.keysym.sym,event.type == SDL_KEYDOWN); + break; + + case SDL_MOUSEMOTION: + _mmove(event.motion.x,event.motion.y); + break; + + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEBUTTONDOWN: + _mbutton(event.button.x,event.button.y,event.type == SDL_MOUSEBUTTONDOWN); + break; + + case SDL_QUIT: + return false; + + default: + break; + } + } + + return true; +} + +void shutdown() +{ + SDL_Quit(); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/gameApp.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,329 @@ +/++ + + Authors: Stephan Dilly, www.extrawurst.org + +/ + +module gameApp; + +import framework; + +import drawSpace; + +import chipmunkd.chipmunk; + +import samples.LogoSmash; +import samples.Simple; +import samples.PyramidStack; +import samples.ChipmunkDemo; +import samples.Plink; +import samples.Tumble; +import samples.PyramidTopple; +import samples.Planet; +import samples.Query; +import samples.OneWay; +import samples.Sensors; +import samples.Bounce; +import samples.Springies; +import samples.Joints; +import samples.MagnetsElectric; +import samples.Player; +import samples.Tank; +import samples.Pump; +import samples.TheoJansen; +import samples.UnsafeOps; + +import derelict.opengl.gl; +import derelict.opengl.glu; +import derelict.sdl.sdl; + +import std.stdio; +import core.thread:Sleep; + +extern(System) ulong GetTickCount(); + +version = TIME_TRIAL; + +cpVect mousePos; +cpVect arrowDirection; + +/// +final class GameApp { + +private: + + chipmunkDemo*[] demos; + chipmunkDemo* currentDemo; + cpSpace* space; + int ticks; + cpBody* mouseBody; + cpConstraint* mouseJoint; + cpVect mousePos_last; + + bool key_up = false; + bool key_down = false; + bool key_left = false; + bool key_right = false; + + bool m_running = true; + + drawSpaceOptions options = { + 0, // drawHash + 0, // drawBB + 1, // drawShapes + 4.0f, // collisionPointSize + 0.0f, // bodyPointSize + 1.5f, // lineThickness + }; + + enum width = 1024; + enum height = 780; + +version(TIME_TRIAL) +{ + void time_trial(int index, int count) + { + currentDemo = demos[index]; + space = currentDemo.initFunc(); + + auto start = .GetTickCount(); + + foreach(i; 0..count) + currentDemo.updateFunc(i); + + auto end = .GetTickCount(); + auto duration = (end - start); + + currentDemo.destroyFunc(); + currentDemo = null; + + writefln("Time(%s) = %s", cast(char)(index + 'a'), duration); + } +} + + /// + public void boot() { + + demos = [ + &LogoSmash, + &Simple, + &PyramidStack, + &Plink, + &Tumble, + &PyramidTopple, + &Bounce, + &Planet, + &Springies, + &Pump, + &TheoJansen, + &MagnetsElectric, + &UnsafeOps, + &Query, + &OneWay, + &Player, + &Sensors, + &Joints, + &Tank, + ]; + + cpInitChipmunk(); + + cp_collision_slop = 0.2f; + +version(TIME_TRIAL) +{ + Sleep(1); + foreach(i; 0..demos.length) + { + //if(i == 'l' - 'a') continue; + time_trial(i, 1000); + } + + m_running = false; + + return; +}//TIME_TRIAL + + //setup framework + framework.startup("chipmunk'd by Stephan Dilly",width,height); + + reshape(width,height); + + glEnableClientState(GL_VERTEX_ARRAY); + + runDemo(demos[0]); + + mouseBody = cpBodyNew(INFINITY, INFINITY); + } + + /// + void runDemo(chipmunkDemo *demo) + { + if(currentDemo) + currentDemo.destroyFunc(); + + currentDemo = demo; + ticks = 0; + mouseJoint = null; + + //maxArbiters = 0; + //maxPoints = 0; + //maxConstraints = 0; + space = currentDemo.initFunc(); + } + + /// + void reshape(int width, int height) + { + glViewport(0, 0, width, height); + + double rx = width / 2.0; + double ry = height / 2.0; + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-rx, rx, -ry, ry, -1.0, 1.0); + glTranslated(0.5, 0.5, 0.0); + } + + /// + public bool update() { + + if(!m_running) return m_running; + + if(!framework.processEvents(&keyEvent,&mouseMove,&mouseButtonEvent)) + return false; + + cpVect newPoint = cpvlerp(mousePos_last, mousePos, 0.25f); + mouseBody.p = newPoint; + mouseBody.v = cpvmult(cpvsub(newPoint, mousePos_last), 60.0f); + mousePos_last = newPoint; + + currentDemo.updateFunc(ticks++); + + // render + + glClearColor(1,1,1,1); + + glClear(GL_COLOR_BUFFER_BIT); + + DrawSpace(space,currentDemo.drawOptions ? currentDemo.drawOptions : &options); + + SDL_GL_SwapBuffers(); + + return m_running; + } + + /// + public void shutdown() { + +version(TIME_TRIAL){}else +{ + currentDemo.destroyFunc(); + + framework.shutdown(); +} + } + + cpVect mouseToSpace(int x, int y) + { + GLdouble model[16]; + glGetDoublev(GL_MODELVIEW_MATRIX, model.ptr); + + GLdouble proj[16]; + glGetDoublev(GL_PROJECTION_MATRIX, proj.ptr); + + GLint view[4]; + glGetIntegerv(GL_VIEWPORT, view.ptr); + + GLdouble mx, my, mz; + gluUnProject(x, height - y, 0.0f, model.ptr, proj.ptr, view.ptr, &mx, &my, &mz); + + return cpv(mx, my); + } + + /// + private void mouseMove(int x,int y) + { + mousePos = mouseToSpace(x,y); + } + + /// + private void mouseButtonEvent(int x,int y,bool _down) + { + if(_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; + } + } + + /// + private 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); + } + + /// + private void keyEvent(int _key,bool _down) + { + int key = _key; + + if(_down) + { + int index = key - 'a'; + + if(0 <= index && index < demos.length){ + runDemo(demos[index]); + } else if(key == '\r'){ + runDemo(currentDemo); + } else if(key == 47){ + options.drawHash = !options.drawHash; + } else if(key == 92){ + options.drawBBs = !options.drawBBs; + } else if(key == 93){ + 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); + } + else + { + if(key == SDLK_UP) key_up = true; + else if(key == SDLK_DOWN) key_down = true; + else if(key == SDLK_LEFT) key_left = true; + else if(key == SDLK_RIGHT) key_right = true; + + set_arrowDirection(); + } + } + else + { + if(key == SDLK_UP) key_up = false; + else if(key == SDLK_DOWN) key_down = false; + else if(key == SDLK_LEFT) key_left = false; + else if(key == SDLK_RIGHT) key_right = false; + + set_arrowDirection(); + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/main.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,39 @@ +/++ + + Authors: Stephan Dilly, www.extrawurst.org + +/ + +module main; + +import gameApp; + +import std.stdio; + +/// +int main(string[] args) { + + try { + + scope auto game = new GameApp(); + game.boot(); + + //game loop + while(true) + { + if(!game.update()) + break; + } + + game.shutdown(); + + writefln("bye !"); + } + catch(Object o) { + + //write out whatever exception is thrown + debug writefln("[exception] E: \"%s\"",o); + + return -1; + } + + return 0; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Bounce.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,102 @@ + +// written in the D programming language + +module samples.Bounce; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +static cpSpace *space; + +static void +update(int ticks) +{ + enum int steps = 3; + enum cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + } +} + +static void +add_box() +{ + enum cpFloat size = 10.0f; + enum cpFloat mass = 1.0f; + + cpVect verts[] = [ + cpv(-size,-size), + cpv(-size, size), + cpv( size, size), + cpv( size,-size), + ]; + + cpFloat radius = cpvlength(cpv(size, size)); + + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, 4, verts.ptr, cpvzero))); + _body.p = cpv(frand()*(640 - 2*radius) - (320 - radius), frand()*(480 - 2*radius) - (240 - radius)); + _body.v = cpvmult(cpv(2*frand() - 1, 2*frand() - 1), 200); + + cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, 4, verts.ptr, cpvzero)); + shape.e = 1.0f; shape.u = 0.0f; +} + +static cpSpace * +init() +{ + cpResetShapeIdCounter(); + + space = cpSpaceNew(); + cpSpaceResizeActiveHash(space, 30.0f, 1000); + space.iterations = 10; + + cpBody *_body; + cpBody *staticBody = &space.staticBody; + cpShape *shape; + + // Create segments around the edge of the screen. + shape = cpSpaceAddShape(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 = cpSpaceAddShape(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 = cpSpaceAddShape(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 = cpSpaceAddShape(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<10; i++) + add_box(); + + _body = cpSpaceAddBody(space, cpBodyNew(100.0f, 10000.0f)); + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(_body, cpv(-75,0), cpv(75,0), 5.0f)); + shape.e = 1.0f; shape.u = 1.0f; + + cpSpaceAddConstraint(space, cpPivotJointNew2(_body, staticBody, cpvzero, cpvzero)); + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Bounce = { + "Bounce", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/ChipmunkDemo.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,33 @@ + +// written in the D programming language + +module samples.ChipmunkDemo; + +import chipmunkd.chipmunk; + +import drawSpace; + +import core.stdc.stdlib; + +alias cpSpace *function() demoInitFunc; +alias void function(int ticks) demoUpdateFunc; +alias void function()demoDestroyFunc; + +struct chipmunkDemo { + string name; + + const drawSpaceOptions *drawOptions; + + demoInitFunc initFunc; + demoUpdateFunc updateFunc; + demoDestroyFunc destroyFunc; +} + +static cpFloat +frand() +{ + return cast(cpFloat)rand()/cast(cpFloat)RAND_MAX; +} + +enum GRABABLE_MASK_BIT = (1<<31); +enum NOT_GRABABLE_MASK = (~GRABABLE_MASK_BIT);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Joints.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,277 @@ + +// written in the D programming language + +module samples.Joints; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +import std.math; + +static cpSpace *space; + +enum M_PI = PI; +enum M_PI_2 = PI*0.5f; + +static cpBody * +addBall(cpVect pos, cpVect boxOffset) +{ + cpFloat radius = 15.0f; + cpFloat mass = 1.0f; + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); + _body.p = cpvadd(pos, boxOffset); + + cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(_body, radius, cpvzero)); + shape.e = 0.0f; shape.u = 0.7f; + + return _body; +} + +static cpBody * +addLever(cpVect pos, cpVect boxOffset) +{ + cpFloat mass = 1.0f; + cpVect a = cpv(0, 15); + cpVect b = cpv(0, -15); + + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForSegment(mass, a, b))); + _body.p = cpvadd(pos, cpvadd(boxOffset, cpv(0, -15))); + + cpShape *shape = cpSpaceAddShape(space, cpSegmentShapeNew(_body, a, b, 5.0f)); + shape.e = 0.0f; shape.u = 0.7f; + + return _body; +} + +static cpBody * +addBar(cpVect pos, cpVect boxOffset) +{ + cpFloat mass = 2.0f; + cpVect a = cpv(0, 30); + cpVect b = cpv(0, -30); + + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForSegment(mass, a, b))); + _body.p = cpvadd(pos, boxOffset); + + cpShape *shape = cpSpaceAddShape(space, cpSegmentShapeNew(_body, a, b, 5.0f)); + shape.e = 0.0f; shape.u = 0.7f; + + return _body; +} + +static cpBody * +addWheel(cpVect pos, cpVect boxOffset) +{ + cpFloat radius = 15.0f; + cpFloat mass = 1.0f; + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); + _body.p = cpvadd(pos, boxOffset); + + cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(_body, radius, cpvzero)); + shape.e = 0.0f; shape.u = 0.7f; + shape.group = 1; // use a group to keep the car parts from colliding + + return _body; +} + +static cpBody * +addChassis(cpVect pos, cpVect boxOffset) +{ + int num = 4; + cpVect verts[] = [ + cpv(-40,-15), + cpv(-40, 15), + cpv( 40, 15), + cpv( 40,-15), + ]; + + + cpFloat mass = 5.0f; + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, num, verts.ptr, cpvzero))); + _body.p = cpvadd(pos, boxOffset); + + cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, num, verts.ptr, cpvzero)); + shape.e = 0.0f; shape.u = 0.7f; + shape.group = 1; // use a group to keep the car parts from colliding + + return _body; +} + +static cpSpace * +init() +{ + space = cpSpaceNew(); + space.iterations = 10; + space.gravity = cpv(0, -100); + space.sleepTimeThreshold = 0.5f; + + cpBody *staticBody = &space.staticBody; + cpShape *shape; + + shape = cpSpaceAddShape(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 = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,120), cpv(320,120), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,0), cpv(320,0), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-120), cpv(320,-120), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(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 = cpSpaceAddShape(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 = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-160,-240), cpv(-160,240), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(0,-240), cpv(0,240), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(160,-240), cpv(160,240), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + cpVect boxOffset; + cpBody *body1; + cpBody *body2; + + cpVect posA = cpv( 50, 60); + cpVect posB = cpv(110, 60); + + // Pin Joints - Link shapes with a solid bar or pin. + // Keeps the anchor points the same distance apart from when the joint was created. + boxOffset = cpv(-320, -240); + body1 = addBall(posA, boxOffset); + body2 = addBall(posB, boxOffset); + cpSpaceAddConstraint(space, cpPinJointNew(body1, body2, cpv(15,0), cpv(-15,0))); + + // Slide Joints - Like pin joints but with a min/max distance. + // Can be used for a cheap approximation of a rope. + boxOffset = cpv(-160, -240); + body1 = addBall(posA, boxOffset); + body2 = addBall(posB, boxOffset); + cpSpaceAddConstraint(space, cpSlideJointNew(body1, body2, cpv(15,0), cpv(-15,0), 20.0f, 40.0f)); + + // Pivot Joints - Holds the two anchor points together. Like a swivel. + boxOffset = cpv(0, -240); + body1 = addBall(posA, boxOffset); + body2 = addBall(posB, boxOffset); + cpSpaceAddConstraint(space, cpPivotJointNew(body1, body2, cpvadd(boxOffset, cpv(80,60)))); + // cpPivotJointNew() takes it's anchor parameter in world coordinates. The anchors are calculated from that + // cpPivotJointNew2() lets you specify the two anchor points explicitly + + // Groove Joints - Like a pivot joint, but one of the anchors is a line segment that the pivot can slide in + boxOffset = cpv(160, -240); + body1 = addBall(posA, boxOffset); + body2 = addBall(posB, boxOffset); + cpSpaceAddConstraint(space, cpGrooveJointNew(body1, body2, cpv(30,30), cpv(30,-30), cpv(-30,0))); + + // Damped Springs + boxOffset = cpv(-320, -120); + body1 = addBall(posA, boxOffset); + body2 = addBall(posB, boxOffset); + cpSpaceAddConstraint(space, cpDampedSpringNew(body1, body2, cpv(15,0), cpv(-15,0), 20.0f, 5.0f, 0.3f)); + + // Damped Rotary Springs + boxOffset = cpv(-160, -120); + body1 = addBar(posA, boxOffset); + body2 = addBar(posB, boxOffset); + // Add some pin joints to hold the circles in place. + cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, cpvadd(boxOffset, posA))); + cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, cpvadd(boxOffset, posB))); + cpSpaceAddConstraint(space, cpDampedRotarySpringNew(body1, body2, 0.0f, 3000.0f, 60.0f)); + + // Rotary Limit Joint + boxOffset = cpv(0, -120); + body1 = addLever(posA, boxOffset); + body2 = addLever(posB, boxOffset); + // Add some pin joints to hold the circles in place. + cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, cpvadd(boxOffset, posA))); + cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, cpvadd(boxOffset, posB))); + // Hold their rotation within 90 degrees of each other. + cpSpaceAddConstraint(space, cpRotaryLimitJointNew(body1, body2, -M_PI_2, M_PI_2)); + + // Ratchet Joint - A rotary ratchet, like a socket wrench + boxOffset = cpv(160, -120); + body1 = addLever(posA, boxOffset); + body2 = addLever(posB, boxOffset); + // Add some pin joints to hold the circles in place. + cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, cpvadd(boxOffset, posA))); + cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, cpvadd(boxOffset, posB))); + // Ratchet every 90 degrees + cpSpaceAddConstraint(space, cpRatchetJointNew(body1, body2, 0.0f, M_PI_2)); + + // Gear Joint - Maintain a specific angular velocity ratio + boxOffset = cpv(-320, 0); + body1 = addBar(posA, boxOffset); + body2 = addBar(posB, boxOffset); + // Add some pin joints to hold the circles in place. + cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, cpvadd(boxOffset, posA))); + cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, cpvadd(boxOffset, posB))); + // Force one to sping 2x as fast as the other + cpSpaceAddConstraint(space, cpGearJointNew(body1, body2, 0.0f, 2.0f)); + + // Simple Motor - Maintain a specific angular relative velocity + boxOffset = cpv(-160, 0); + body1 = addBar(posA, boxOffset); + body2 = addBar(posB, boxOffset); + // Add some pin joints to hold the circles in place. + cpSpaceAddConstraint(space, cpPivotJointNew(body1, staticBody, cpvadd(boxOffset, posA))); + cpSpaceAddConstraint(space, cpPivotJointNew(body2, staticBody, cpvadd(boxOffset, posB))); + // Make them spin at 1/2 revolution per second in relation to each other. + cpSpaceAddConstraint(space, cpSimpleMotorNew(body1, body2, M_PI)); + + // Make a car with some nice soft suspension + boxOffset = cpv(0, 0); + cpBody *wheel1 = addWheel(posA, boxOffset); + cpBody *wheel2 = addWheel(posB, boxOffset); + cpBody *chassis = addChassis(cpv(80, 100), boxOffset); + + cpSpaceAddConstraint(space, cpGrooveJointNew(chassis, wheel1, cpv(-30, -10), cpv(-30, -40), cpvzero)); + cpSpaceAddConstraint(space, cpGrooveJointNew(chassis, wheel2, cpv( 30, -10), cpv( 30, -40), cpvzero)); + + cpSpaceAddConstraint(space, cpDampedSpringNew(chassis, wheel1, cpv(-30, 0), cpvzero, 50.0f, 20.0f, 1.5f)); + cpSpaceAddConstraint(space, cpDampedSpringNew(chassis, wheel2, cpv( 30, 0), cpvzero, 50.0f, 20.0f, 1.5f)); + + return space; +} + +static void +update(int ticks) +{ + cpSpaceStep(space, 1.0f/60.0f); +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Joints = { + "Joints and Constraints", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/LogoSmash.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,135 @@ + +// written in the D programming language + +module samples.LogoSmash; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +import drawSpace; + +enum int image_width = 188; +enum int image_height = 35; +enum int image_row_length = 24; + +enum byte[] image_bitmap = [ + 15,-16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,-64,15,63,-32,-2,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,31,-64,15,127,-125,-1,-128,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,127,-64,15,127,15,-1,-64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-1,-64,15,-2, + 31,-1,-64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-1,-64,0,-4,63,-1,-32,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,1,-1,-64,15,-8,127,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,-1,-64,0,-8,-15,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,-31,-1,-64,15,-8,-32, + -1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,-15,-1,-64,9,-15,-32,-1,-32,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,31,-15,-1,-64,0,-15,-32,-1,-32,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,63,-7,-1,-64,9,-29,-32,127,-61,-16,63,15,-61,-1,-8,31,-16,15,-8,126,7,-31, + -8,31,-65,-7,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-2,63,-8,31,-4,-1,15,-13, + -4,63,-1,-3,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-2,63,-8,31,-4,-1,15,-13, + -2,63,-1,-3,-1,-64,9,-29,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13, + -2,63,-33,-1,-1,-32,9,-25,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13, + -1,63,-33,-1,-1,-16,9,-25,-32,0,7,-8,127,-97,-25,-1,-1,63,-4,63,-4,-1,15,-13, + -1,63,-49,-1,-1,-8,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13, + -1,-65,-49,-1,-1,-4,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13, + -1,-65,-57,-1,-1,-2,9,-57,-32,0,7,-8,127,-97,-25,-8,-1,63,-2,127,-4,-1,15,-13, + -1,-1,-57,-1,-1,-1,9,-57,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1, + -1,-61,-1,-1,-1,-119,-57,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1, + -1,-61,-1,-1,-1,-55,-49,-32,0,7,-1,-1,-97,-25,-8,-1,63,-1,-1,-4,-1,15,-13,-1, + -1,-63,-1,-1,-1,-23,-49,-32,127,-57,-1,-1,-97,-25,-1,-1,63,-1,-1,-4,-1,15,-13, + -1,-1,-63,-1,-1,-1,-16,-49,-32,-1,-25,-1,-1,-97,-25,-1,-1,63,-33,-5,-4,-1,15, + -13,-1,-1,-64,-1,-9,-1,-7,-49,-32,-1,-25,-8,127,-97,-25,-1,-1,63,-33,-5,-4,-1, + 15,-13,-1,-1,-64,-1,-13,-1,-32,-49,-32,-1,-25,-8,127,-97,-25,-1,-2,63,-49,-13, + -4,-1,15,-13,-1,-1,-64,127,-7,-1,-119,-17,-15,-1,-25,-8,127,-97,-25,-1,-2,63, + -49,-13,-4,-1,15,-13,-3,-1,-64,127,-8,-2,15,-17,-1,-1,-25,-8,127,-97,-25,-1, + -8,63,-49,-13,-4,-1,15,-13,-3,-1,-64,63,-4,120,0,-17,-1,-1,-25,-8,127,-97,-25, + -8,0,63,-57,-29,-4,-1,15,-13,-4,-1,-64,63,-4,0,15,-17,-1,-1,-25,-8,127,-97, + -25,-8,0,63,-57,-29,-4,-1,-1,-13,-4,-1,-64,31,-2,0,0,103,-1,-1,-57,-8,127,-97, + -25,-8,0,63,-57,-29,-4,-1,-1,-13,-4,127,-64,31,-2,0,15,103,-1,-1,-57,-8,127, + -97,-25,-8,0,63,-61,-61,-4,127,-1,-29,-4,127,-64,15,-8,0,0,55,-1,-1,-121,-8, + 127,-97,-25,-8,0,63,-61,-61,-4,127,-1,-29,-4,63,-64,15,-32,0,0,23,-1,-2,3,-16, + 63,15,-61,-16,0,31,-127,-127,-8,31,-1,-127,-8,31,-128,7,-128,0,0 +]; + +static int +get_pixel(int x, int y) +{ + return (image_bitmap[(x>>3) + y*image_row_length]>>(~x&0x7)) & 1; +} + +static cpSpace *space; + +static void +update(int ticks) +{ + enum int steps = 1; + enum cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + } +} + +static cpShape * +make_ball(cpFloat x, cpFloat y) +{ + cpBody *_body = cpBodyNew(1.0f, INFINITY); + _body.p = cpv(x, y); + + cpShape *shape = cpCircleShapeNew(_body, 0.95f, cpvzero); + shape.e = 0.0f; shape.u = 0.0f; + + return shape; +} + +static cpSpace * +init() +{ + space = cpSpaceNew(); + cpSpaceResizeActiveHash(space, 2.0f, 10000); + cpSpaceResizeStaticHash(space, 2.0f, 10000); + space.iterations = 1; + + cpBody *_body; + cpShape *shape; + + for(int y=0; y<image_height; y++){ + for(int x=0; x<image_width; x++){ + if(!get_pixel(x, y)) continue; + + cpFloat x_jitter = 0.05f*frand(); + cpFloat y_jitter = 0.05f*frand(); + + shape = make_ball(2*(x - image_width/2 + x_jitter), 2*(image_height/2 - y + y_jitter)); + cpSpaceAddBody(space, shape._body); + cpSpaceAddShape(space, shape); + } + } + + _body = cpSpaceAddBody(space, cpBodyNew(INFINITY, INFINITY)); + _body.p = cpv(-1000.0f, -10.0f); + _body.v = cpv(400.0f, 0.0f); + + shape = cpSpaceAddShape(space, cpCircleShapeNew(_body, 8.0f, cpvzero)); + shape.e = 0.0f; shape.u = 0.0f; + shape.layers = NOT_GRABABLE_MASK; + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +static const drawSpaceOptions draw_options = { + 0, 0, 0, 2.0f, 3.0f, 0.0f, +}; + +chipmunkDemo LogoSmash = { + "Logo Smash", + &draw_options, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/MagnetsElectric.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,503 @@ + +// written in the D programming language + +module samples.MagnetsElectric; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +import std.math; +import core.stdc.string:strcmp; +import core.stdc.stdio:sprintf; + +enum WIDTH = 600; +enum HEIGHT = 400; + +enum SINGMAX = 10; // Maximum number of singularities per body +enum NMAG = 10; // Number of magnets +enum NCHG = 10; // Number of charged bodies +enum NMIX = 10; // Number of charged magnets + +enum COU_MKS = 8.987551787e9; // Some physical constants +enum MAG_MKS = 1e-7; + +// Prototypes +alias void function(DataforForce* data)SingForceFunc; + +// Structures +// Singularities +struct ActorSingularity{ + // Number of singularities + int Nsing; + // Value of the singularities + cpFloat value[SINGMAX]; + // Type of the singularities + char type[SINGMAX][100]; + // Global position of the singularities + cpVect Gpos[SINGMAX]; + // Local position of the singularities + cpVect position[SINGMAX]; + // Angle of the singularities measured in the body axes + cpFloat angle[SINGMAX]; + // Angle of the singularities measured from x + cpFloat Gangle[SINGMAX]; + // Force function + SingForceFunc force_func[SINGMAX]; + // Force function + SingForceFunc torque_func[SINGMAX]; +} +alias ActorSingularity Sing; + +// Data for the force functions +struct DataforForce{ + //Everything in global coordinates + // Position of the source + cpVect p0; + // Observed position + cpVect p; + // Relative position source-observed + cpVect relp; + // distance, disntace^2, ditance ^3 + cpFloat r[3]; + // angle of the source + cpFloat ang0; + // angle of the observed singularity + cpFloat ang; + // Foce value + cpVect F; + // Torque value + cpFloat T; +} +alias DataforForce ForceData; + +// Global Varibales +static cpSpace *space; + + +// **** Forces ****** // +// Calculate the forces between two bodies. all this functions requieres +// a pointer to an structure with the necessary fields. + +// forces between charges +static void +CoulombForce(ForceData* data){ + data.F=cpvmult(cpvnormalize(data.relp),COU_MKS/data.r[1]); +} + +// forces between magnets +static void +MagDipoleForce(ForceData* data){ + static cpFloat phi,alpha,beta,Fr,Fphi; + + // Angle of the relative position vector + phi=cpvtoangle(data.relp); + alpha=data.ang0; + beta=data.ang; + + alpha =phi - alpha; + beta = phi - beta; + + + // Components in polar coordinates + Fr=(2.0e0*cos(alpha)*cos(beta) - sin(alpha)*sin(beta)); + Fphi=sin(alpha+beta); +// printf("%g %g %g %g %g\n",phi,alpha,beta,Fphi); + + // Cartesian coordinates + data.F=cpv(Fr*cos(phi)-Fphi*sin(phi),Fr*sin(phi)+Fphi*cos(phi)); + data.F=cpvmult(data.F,-3.e0*MAG_MKS/(data.r[1]*data.r[1])); +} + +static void +MagDipoleTorque(ForceData* data){ + static cpFloat phi,alpha,beta; + + phi=cpvtoangle(data.relp); + alpha=data.ang0; + beta=data.ang; + alpha =phi - alpha; + beta = phi - beta; + + // Torque. Though we could use a component of F to save some space, + // we use another variables for the sake of clarity. + + data.T=(MAG_MKS/data.r[2])*(3.0e0*cos(alpha)*sin(beta) + sin(alpha-beta)); +} +// ******* // + +// This function fills the data structure for the force functions +// The structure Sing has the information about the singularity (charge or magnet) +static void +FillForceData(Sing* source,int inds, Sing* obs,int indo, ForceData* data) +{ + // Global Position and orientation of the source singularity + data.p0=source.Gpos[inds]; + data.ang0=source.Gangle[inds]; + + // Global Position and orientation of the observed singularity + data.p=obs.Gpos[indo]; + data.ang=obs.Gangle[indo]; + + // Derived magnitudes + data.relp=cpvsub(data.p,data.p0); //Relative position + data.r[0]=cpvlength(data.relp); // Distance + data.r[1]=cpvlengthsq(data.relp); // Square Distance + data.r[2]=data.r[0]*data.r[1]; // Cubic distance + + source.force_func[inds](data); // The value of the force + data.F= cpvmult(data.F,source.value[inds]*obs.value[indo]); +} + +// Calculation of the interaction +static void +LRangeForceApply(cpBody *a, cpBody *b){ + + Sing* aux = cast(Sing*)a.data; + Sing* aux2 = cast(Sing*)b.data; + cpVect delta; + // General data needed to calculate interaction + static ForceData fdata; + fdata.F=cpvzero; + + // Calculate the forces between the charges of different bodies + for (int i=0; i<aux.Nsing; i++) + { + for (int j=0; j<aux2.Nsing; j++) + { + if(!strcmp(aux.type[i].ptr,aux2.type[j].ptr)) + { + //printf("%s %s\n",aux.type[i],aux2.type[j]); + FillForceData (aux2,j,aux,i,&fdata); + + //Force applied to body A + delta=cpvsub(aux.Gpos[i], a.p); + cpBodyApplyForce(a,fdata.F, delta); + + if(aux.torque_func[i] != null) + { + //Torque on A + aux.torque_func[i](&fdata); + a.t += aux.value[i]*aux2.value[j]*fdata.T; + + } + } + } + } +} + +// function for the integration of the positions +// The following functions are variations to the starndrd integration in Chipmunk +// you can go ack to the standard ones by doing the appropiate changes. +static void +ChargedBodyUpdatePositionVerlet(cpBody *_body, cpFloat dt) +{ + // Long range interaction + cpArray *bodies = space.bodies; + static cpBody* B; + Sing* aux=cast(Sing*)_body.data; + Sing* aux2; + + // General data needed to calculate interaction + static ForceData fdata; + fdata.F=cpvzero; + + for(int i=0; i< bodies.num; i++) + { + B=cast(cpBody*)bodies.arr[i]; + aux2=cast(Sing*)B.data; + + if(B != _body) + { + // Calculate the forces between the singularities of different bodies + LRangeForceApply(_body, B); + } + } + + cpVect dp = cpvmult(cpvadd(_body.v, _body.v_bias), dt); + dp = cpvadd(dp,cpvmult(cpvmult(_body.f, _body.m_inv), 0.5e0*dt*dt)); + _body.p = cpvadd(_body.p, dp); + + cpBodySetAngle(_body, cast(float)(_body.a + (_body.w + _body.w_bias)*dt + + 0.5*_body.t*_body.i_inv*dt*dt)); + + // Update position of the singularities + aux = cast(Sing*)_body.data; + for (int i=0; i<aux.Nsing; i++) + { + aux.Gpos[i]=cpvadd(_body.p,cpvrotate(cpv(aux.position[i].x, + aux.position[i].y), _body.rot)); + aux.Gangle[i]= aux.angle[i] + _body.a; + } + + + _body.v_bias = cpvzero; + _body.w_bias = 0.0f; +} + +// function for the integration of the velocities +static void +ChargedBodyUpdateVelocityVerlet(cpBody *_body, cpVect gravity, cpFloat damping, cpFloat dt) +{ + _body.v = cpvadd(_body.v, cpvmult(cpvadd(gravity, cpvmult(_body.f, _body.m_inv)), 0.5e0*dt)); + _body.w = _body.w + _body.t*_body.i_inv*0.5e0*dt; + + _body.f = cpvzero; + _body.t = 0.0e0; + + // Long range interaction + cpArray *bodies = space.bodies; + static cpBody* B; + + // General data needed to calculate interaction + static ForceData fdata; + fdata.F=cpvzero; + + for(int i=0; i< bodies.num; i++) + { + B=cast(cpBody*)bodies.arr[i]; + + if(B != _body) + { + // Calculate the forces between the singularities of different bodies + LRangeForceApply(_body, B); + } + } + _body.v = cpvadd(cpvmult(_body.v,damping), cpvmult(cpvadd(gravity, cpvmult(_body.f, _body.m_inv)), 0.5e0*dt)); + _body.w = _body.w*damping + _body.t*_body.i_inv*0.5e0*dt; +} + +static void +update(int ticks) +{ + enum int steps = 10; + enum cpFloat dt = 1.0/60.0/cast(cpFloat)steps; + + cpArray *bodies = space.bodies; + + for(int i=0; i< bodies.num; i++) + cpBodyResetForces(cast(cpBody*)bodies.arr[i]); + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + } + +} + +static void +make_mag(cpVect p, cpFloat ang, cpFloat mag) +{ + int nverts=6; + cpVect verts[] = [ + cpv(-10,-10), + cpv(-10, 10), + cpv( 10, 10), + cpv( 15, 5), + cpv( 15, -5), + cpv( 10,-10) + ]; + + cpBody *_body = cpBodyNew(1.0, cpMomentForPoly(1.0f, nverts, verts.ptr, cpvzero)); + _body.p = p; + _body.v = cpvzero; + cpBodySetAngle(_body, ang); + _body.w = 0.0e0; + + // Load the singularities + Sing *magnet=cast(Sing*)cpmalloc(Sing.sizeof); + magnet.Nsing=1; + magnet.value[0]=mag; + sprintf(magnet.type[0].ptr,"magdipole"); + + // The position and angle could be different form the one of the body + magnet.position[0]=cpvzero; + magnet.Gpos[0]=cpvadd(p,magnet.position[0]); + magnet.angle[0]=0.0f; + magnet.Gangle[0]=ang; + + magnet.force_func[0]=&MagDipoleForce; + magnet.torque_func[0]=&MagDipoleTorque; + + _body.data=magnet; + + _body.position_func=&ChargedBodyUpdatePositionVerlet; + _body.velocity_func=&ChargedBodyUpdateVelocityVerlet; + cpSpaceAddBody(space, _body); + + cpShape *shape = cpPolyShapeNew(_body, nverts, verts.ptr, cpvzero); + shape.e = 0.0; shape.u = 0.7; + cpSpaceAddShape(space, shape); +} + +static void +make_charged(cpVect p, cpFloat chg) +{ + int nverts=4; + cpVect verts[] = [ + cpv(-10,-10), + cpv(-10, 10), + cpv( 10, 10), + cpv( 10,-10) + ]; + + cpBody *_body = cpBodyNew(1.0, cpMomentForPoly(1.0, nverts, verts.ptr, cpvzero)); + _body.p = p; + _body.v = cpvzero; + cpBodySetAngle(_body, 0.0f); + _body.w = 0.0e0; + + // Load the singularities + Sing *charge=cast(Sing*)cpmalloc(Sing.sizeof);; + charge.Nsing=1; + charge.value[0]=chg; + sprintf(charge.type[0].ptr,"electrical\0"); + + // The position and angle could be different form the one of the body + charge.position[0]=cpvzero; + charge.Gpos[0]=cpvadd(p,charge.position[0]); + charge.Gangle[0]=0; + + charge.force_func[0]=&CoulombForce; + charge.torque_func[0]=null; + + _body.data=charge; + + _body.position_func=&ChargedBodyUpdatePositionVerlet; + _body.velocity_func=&ChargedBodyUpdateVelocityVerlet; + cpSpaceAddBody(space, _body); + + cpShape *shape = cpPolyShapeNew(_body, nverts, verts.ptr, cpvzero); + shape.e = 0.0; shape.u = 0.7; + cpSpaceAddShape(space, shape); +} +void +make_mix(cpVect p, cpFloat ang, cpFloat mag,cpFloat chg) +{ + int nverts=5; + cpVect verts[] = [ + cpv(-10,-10), + cpv(-10, 10), + cpv( 10, 10), + cpv( 20, 0), + cpv( 10,-10) + ]; + + cpBody *_body = cpBodyNew(1.0, cpMomentForPoly(1.0, nverts, verts.ptr, cpvzero)); + _body.p = p; + _body.v = cpvzero; + cpBodySetAngle(_body, ang); + _body.w = 0.0e0; + + // Load the singularities + Sing *mix=cast(Sing*)cpmalloc(Sing.sizeof);; + mix.Nsing=2; + mix.value[0]=mag; + mix.value[1]=chg; + sprintf(mix.type[0].ptr,"magdipole\0"); + sprintf(mix.type[1].ptr,"electrical\0"); + + // The position and angle could be different form the one of the body + mix.position[0]=cpvzero; + mix.Gpos[0]=cpvadd(p,mix.position[0]); + mix.position[1]=cpvzero; + mix.Gpos[1]=cpvadd(p,mix.position[1]); + mix.Gangle[0]=ang; + mix.Gangle[1]=ang; + + mix.force_func[0]=&MagDipoleForce; + mix.force_func[1]=&CoulombForce; + mix.torque_func[0]=&MagDipoleTorque; + mix.torque_func[1]=null; + + _body.data=mix; + + _body.position_func=&ChargedBodyUpdatePositionVerlet; + _body.velocity_func=&ChargedBodyUpdateVelocityVerlet; + cpSpaceAddBody(space, _body); + + cpShape *shape = cpPolyShapeNew(_body, nverts, verts.ptr, cpvzero); + shape.e = 0.0; shape.u = 0.7; + cpSpaceAddShape(space, shape); +} + + +static cpSpace* +init() +{ + cpResetShapeIdCounter(); + space = cpSpaceNew(); + space.iterations = 5; + space.gravity = cpvzero; //cpv(0,-100); + + cpSpaceResizeActiveHash(space, 30.0, 2999); + + // Screen border +/* shape = cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(-320,240), 0.0f); + shape.e = 1.0; shape.u = 1.0; + cpSpaceAddShape(space, shape); + + shape = cpSegmentShapeNew(staticBody, cpv(320,-240), cpv(320,240), 0.0f); + shape.e = 1.0; shape.u = 1.0; + cpSpaceAddShape(space, shape); + + shape = cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f); + shape.e = 1.0; shape.u = 1.0; + cpSpaceAddShape(space, shape); + + // Reference line + // Does not collide with other objects, we just want to draw it. + shape = cpSegmentShapeNew(staticBody, cpv(-320,0), cpv(320,0), 0.0f); + shape.collision_type = 1; + cpSpaceAddShape(space, shape); + // Add a collision pair function to filter collisions + cpSpaceAddCollisionPairFunc(space, 0, 1, null, null); +*/ + + //srand(cast(uint) time(null)); + cpVect p; + cpFloat ang; + + // Create magnets + for(int i=0; i<NMAG; i++) + { + p.x=(2.0e0*frand() - 1.0e0)*WIDTH/2.0f; + p.y=(2.0e0*frand() - 1.0e0)*HEIGHT/2.0f; + ang=(2.0e0*frand() - 1.0e0)*3.1415; + make_mag(p, ang,1.0e7); + } + + // Create charged objects + for(int i=0; i<NCHG; i++) + { + p.x=(2.0e0*frand() - 1.0e0)*WIDTH/2.0f; + p.y=(2.0e0*frand() - 1.0e0)*HEIGHT/2.0f; + ang=(2.0e0*frand() - 1.0e0)*3.1415; + make_charged(p,1.0e-3*pow(-1.0,i%2)); + } + + // Create charged magnets objects + for(int i=0; i<NMIX; i++) + { + p.x=(2.0e0*frand() - 1.0e0)*WIDTH/2.0f; + p.y=(2.0e0*frand() - 1.0e0)*HEIGHT/2.0f; + ang=(2.0e0*frand() - 1.0e0)*3.1415; + make_mix(p, ang,1.0e7*pow(-1.0,i%2), 1.0e-3*pow(-1.0,i%2)); + } + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo MagnetsElectric = { + "Magnets and Electric Charges (By: Juan Pablo Carbajal)", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/OneWay.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,112 @@ + +// written in the D programming language + +module samples.OneWay; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +static cpSpace *space; + +struct OneWayPlatform { + cpVect n; // direction objects may pass through + cpArray *passThruList; // list of objects passing through +} + +static OneWayPlatform platformInstance; + +static cpBool +preSolve(cpArbiter *arb, cpSpace *space, void *ignore) +{ + mixin(CP_ARBITER_GET_SHAPES!("arb", "a", "b")); + OneWayPlatform *platform = cast(OneWayPlatform *)a.data; + + if(cpvdot(cpArbiterGetNormal(arb, 0), platform.n) < 0){ + cpArbiterIgnore(arb); + return cpFalse; + } + + return cpTrue; +} + +static void +update(int ticks) +{ + int steps = 1; + cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + } +} + +static cpSpace * +init() +{ + cpResetShapeIdCounter(); + + space = cpSpaceNew(); + space.iterations = 10; + space.gravity = cpv(0, -100); + + cpBody *_body; + cpBody *staticBody = &space.staticBody; + cpShape *shape; + + // Create segments around the edge of the screen. + shape = cpSpaceAddShape(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 = cpSpaceAddShape(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 = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + // Add our one way segment + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-160,-100), cpv(160,-100), 10.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.collision_type = 1; + shape.layers = NOT_GRABABLE_MASK; + + // We'll use the data pointer for the OneWayPlatform struct + platformInstance.n = cpv(0, 1); // let objects pass upwards + platformInstance.passThruList = cpArrayNew(0); + shape.data = &platformInstance; + + + // Add a ball to make things more interesting + cpFloat radius = 15.0f; + _body = cpSpaceAddBody(space, cpBodyNew(10.0f, cpMomentForCircle(10.0f, 0.0f, radius, cpvzero))); + _body.p = cpv(0, -200); + _body.v = cpv(0, 170); + + shape = cpSpaceAddShape(space, cpCircleShapeNew(_body, radius, cpvzero)); + shape.e = 0.0f; shape.u = 0.9f; + shape.collision_type = 2; + + cpSpaceAddCollisionHandler(space, 1, 2, null, &preSolve, null, null, null); + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); + + cpArrayFree(platformInstance.passThruList); +} + +chipmunkDemo OneWay = { + "One Way Platforms", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Planet.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,123 @@ + +// written in the D programming language + +module samples.Planet; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +static cpSpace *space; +static cpBody *planetBody; + +static cpFloat gravityStrength = 5.0e6f; + +static void +update(int ticks) +{ + int steps = 1; + cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + + // Update the static body spin so that it looks like it's rotating. + cpBodyUpdatePosition(planetBody, dt); + } +} + +static void +planetGravityVelocityFunc(cpBody *_body, cpVect gravity, cpFloat damping, cpFloat dt) +{ + // Gravitational acceleration is proportional to the inverse square of + // distance, and directed toward the origin. The central planet is assumed + // to be massive enough that it affects the satellites but not vice versa. + cpVect p = _body.p; + cpFloat sqdist = cpvlengthsq(p); + cpVect g = cpvmult(p, -gravityStrength / (sqdist * cpfsqrt(sqdist))); + + cpBodyUpdateVelocity(_body, g, damping, dt); +} + +static cpVect +rand_pos(cpFloat radius) +{ + cpVect v; + do { + v = cpv(frand()*(640 - 2*radius) - (320 - radius), frand()*(480 - 2*radius) - (240 - radius)); + } while(cpvlength(v) < 85.0f); + + return v; +} + +static void +add_box() +{ + const cpFloat size = 10.0f; + const cpFloat mass = 1.0f; + + cpVect verts[] = [ + cpv(-size,-size), + cpv(-size, size), + cpv( size, size), + cpv( size,-size), + ]; + + cpFloat radius = cpvlength(cpv(size, size)); + + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, 4, verts.ptr, cpvzero))); + _body.velocity_func = &planetGravityVelocityFunc; + _body.p = rand_pos(radius); + + // Set the box's velocity to put it into a circular orbit from its + // starting position. + cpFloat r = cpvlength(_body.p); + cpFloat v = cpfsqrt(gravityStrength / r) / r; + _body.v = cpvmult(cpvperp(_body.p), v); + + // Set the box's angular velocity to match its orbital period and + // align its initial angle with its position. + _body.w = v; + cpBodySetAngle(_body, cpfatan2(_body.p.y, _body.p.x)); + + cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, 4, verts.ptr, cpvzero)); + shape.e = 0.0f; shape.u = 0.7f; +} + +static cpSpace * +init() +{ + planetBody = cpBodyNew(INFINITY, INFINITY); + planetBody.w = 0.2f; + + cpResetShapeIdCounter(); + + space = cpSpaceNew(); + cpSpaceResizeActiveHash(space, 30.0f, 10000); + space.iterations = 20; + + for(int i=0; i<30; i++) + add_box(); + + cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(planetBody, 70.0f, cpvzero)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + return space; +} + +static void +destroy() +{ + cpBodyFree(planetBody); + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Planet = { + "Planet", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Player.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,208 @@ + +// written in the D programming language + +module samples.Player; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +import gameApp; + +static cpSpace *space; + +struct PlayerStruct { + cpFloat u; + cpShape *shape; + cpVect groundNormal; + cpArray *groundShapes; +} + +PlayerStruct playerInstance; + +static cpBool +begin(cpArbiter *arb, cpSpace *space, void *ignore) +{ + mixin(CP_ARBITER_GET_SHAPES!("arb", "a", "b")); + PlayerStruct *player = cast(PlayerStruct *)a.data; + + cpVect n = cpvneg(cpArbiterGetNormal(arb, 0)); + if(n.y > 0.0f){ + cpArrayPush(player.groundShapes, b); + } + + return cpTrue; +} + +static cpBool +preSolve(cpArbiter *arb, cpSpace *space, void *ignore) +{ + mixin(CP_ARBITER_GET_SHAPES!("arb", "a", "b")); + PlayerStruct *player = cast(PlayerStruct *)a.data; + + if(cpArbiterIsFirstContact(arb)){ + a.u = player.u; + + // pick the most upright jump normal each frame + cpVect n = cpvneg(cpArbiterGetNormal(arb, 0)); + if(n.y >= player.groundNormal.y){ + player.groundNormal = n; + } + } + + return cpTrue; +} + +static void +separate(cpArbiter *arb, cpSpace *space, void *ignore) +{ + mixin(CP_ARBITER_GET_SHAPES!("arb", "a", "b")); + PlayerStruct *player = cast(PlayerStruct *)a.data; + + cpArrayDeleteObj(player.groundShapes, b); + + if(player.groundShapes.num == 0){ + a.u = 0.0f; + player.groundNormal = cpvzero; + } +} + +static void +playerUpdateVelocity(cpBody *_body, cpVect gravity, cpFloat damping, cpFloat dt) +{ + cpBodyUpdateVelocity(_body, gravity, damping, dt); + _body.v.y = cpfmax(_body.v.y, -700); + _body.v.x = cpfclamp(_body.v.x, -400, 400); +} + + +static void +update(int ticks) +{ + static int lastJumpState = 0; + int jumpState = (arrowDirection.y > 0.0f); + + cpBody *_body = playerInstance.shape._body; + + cpVect groundNormal = playerInstance.groundNormal; + if(groundNormal.y > 0.0f){ + playerInstance.shape.surface_v = cpvmult(cpvperp(groundNormal), 400.0f*arrowDirection.x); + if(arrowDirection.x) cpBodyActivate(_body); + } else { + playerInstance.shape.surface_v = cpvzero; + } + + // apply jump + if(jumpState && !lastJumpState && cpvlengthsq(groundNormal)){ +// body.v = cpvmult(cpvslerp(groundNormal, cpv(0.0f, 1.0f), 0.5f), 500.0f); + _body.v = cpvadd(_body.v, cpvmult(cpvslerp(groundNormal, cpv(0.0f, 1.0f), 0.75f), 500.0f)); + cpBodyActivate(_body); + } + + if(playerInstance.groundShapes.num == 0){ + cpFloat air_accel = _body.v.x + arrowDirection.x*(2000.0f); + _body.f.x = _body.m*air_accel; +// body.v.x = cpflerpconst(body.v.x, 400.0f*arrowDirection.x, 2000.0f/60.0f); + } + + enum int steps = 3; + enum cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + } + + lastJumpState = jumpState; +} + +static cpSpace * +init() +{ + cpResetShapeIdCounter(); + + space = cpSpaceNew(); + space.iterations = 10; + space.gravity = cpv(0, -1500); + + cpBody *_body; + cpBody *staticBody = &space.staticBody; + cpShape *shape; + + // Create segments around the edge of the screen. + shape = cpSpaceAddShape(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.collision_type = 2; + + shape = cpSpaceAddShape(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.collision_type = 2; + + shape = cpSpaceAddShape(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.collision_type = 2; + + shape = cpSpaceAddShape(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.collision_type = 2; + + // add some other segments to play with + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-220,-200), cpv(-220,240), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + shape.collision_type = 2; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(0,-240), cpv(320,-200), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + shape.collision_type = 2; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(200,-240), cpv(320,-100), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + shape.collision_type = 2; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-220,-80), cpv(200,-80), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + shape.collision_type = 2; + + // Set up the player + cpFloat radius = 15.0f; + _body = cpSpaceAddBody(space, cpBodyNew(10.0f, INFINITY)); + _body.p = cpv(0, -220); + _body.velocity_func = &playerUpdateVelocity; + + shape = cpSpaceAddShape(space, cpCircleShapeNew(_body, radius, cpvzero)); + shape.e = 0.0f; shape.u = 2.0f; + shape.collision_type = 1; + + playerInstance.u = shape.u; + playerInstance.shape = shape; + playerInstance.groundShapes = cpArrayNew(0); + shape.data = &playerInstance; + + cpSpaceAddCollisionHandler(space, 1, 2, &begin, &preSolve, null, &separate, null); + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); + + cpArrayFree(playerInstance.groundShapes); +} + +chipmunkDemo Player = { + "Player", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Plink.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,112 @@ + +// written in the D programming language + +module samples.Plink; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +import std.math; + +static cpSpace *space; + +// Iterate over all of the bodies and reset the ones that have fallen offscreen. +static void +eachBody(cpBody *_body, void *unused) +{ + if(_body.p.y < -260 || cpfabs(_body.p.x) > 340){ + cpFloat x = frand()*640 - 320; + _body.p = cpv(x, 260); + } +} + +static void +update(int ticks) +{ + int steps = 1; + cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + cpSpaceEachBody(space, &eachBody, null); + } +} + +enum NUM_VERTS = 5; + +static cpSpace * +init() +{ + cpResetShapeIdCounter(); + + space = cpSpaceNew(); + space.iterations = 5; + space.gravity = cpv(0, -100); + + cpSpaceResizeStaticHash(space, 40.0f, 999); + cpSpaceResizeActiveHash(space, 30.0f, 2999); + + cpBody *_body; + cpBody *staticBody = &space.staticBody; + cpShape *shape; + + // Create vertexes for a pentagon shape. + cpVect verts[NUM_VERTS]; + for(int i=0; i<NUM_VERTS; i++){ + cpFloat angle = -2.0f*PI*i/(cast(cpFloat) NUM_VERTS); + verts[i] = cpv(10.0f*cos(angle), 10.0f*sin(angle)); + } + + // Vertexes for a triangle shape. + enum cpVect tris[] = [ + cpv(-15,-15), + cpv( 0, 10), + cpv( 15,-15), + ]; + + int foo; + + // Create the static triangles. + foreach(i; 0..9){ + foreach(j; 0..6){ + cpFloat stagger = (j%2)*40; + cpVect offset; + offset.x = (i*80) - 320 + stagger; + offset.y = (j*70) - 240; + //BUG: crazy fucking dmd codegen bug when optimizing (2.050) + foo = i; + + shape = cpSpaceAddShape(space, cpPolyShapeNew(staticBody, 3, tris.ptr, offset)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + } + } + + // Add lots of pentagons. + for(int i=0; i<300; i++){ + _body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, NUM_VERTS, verts.ptr, cpvzero))); + cpFloat x = frand()*640 - 320; + _body.p = cpv(x, 350); + + shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, NUM_VERTS, verts.ptr, cpvzero)); + shape.e = 0.0f; shape.u = 0.4f; + } + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Plink = { + "Plink", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Pump.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,173 @@ + +// written in the D programming language + +module samples.Pump; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +import gameApp; + +import std.math; + +enum M_PI = PI; +enum M_PI_2 = PI*0.5f; + +static cpSpace *space; +static cpConstraint *motor; + +enum numBalls = 5; +static cpBody *balls[numBalls]; + +static void +update(int ticks) +{ + cpFloat coef = (2.0f + arrowDirection.y)/3.0f; + cpFloat rate = arrowDirection.x*30.0f*coef; + + cpSimpleMotorSetRate(motor, rate); + motor.maxForce = (rate ? 1000000.0f : 0.0f); + + enum int steps = 2; + enum cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + + for(int j=0; j<numBalls; j++){ + cpBody *ball = balls[j]; + if(ball.p.x > 320.0f){ + ball.v = cpvzero; + ball.p = cpv(-224.0f, 200.0f); + } + } + } +} + +static cpBody * +add_ball(cpVect pos) +{ + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForCircle(1.0f, 30, 0, cpvzero))); + _body.p = pos; + + cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(_body, 30, cpvzero)); + shape.e = 0.0f; shape.u = 0.5f; + + return _body; +} + +static cpSpace * +init() +{ + space = cpSpaceNew(); + space.gravity = cpv(0, -600); + + cpBody *staticBody = &space.staticBody; + cpShape *shape; + + // beveling all of the line segments slightly helps prevent things from getting stuck on cracks + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-256,16), cpv(-256,300), 2.0f)); + shape.e = 0.0f; shape.u = 0.5f; shape.layers = 1; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-256,16), cpv(-192,0), 2.0f)); + shape.e = 0.0f; shape.u = 0.5f; shape.layers = 1; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-192,0), cpv(-192, -64), 2.0f)); + shape.e = 0.0f; shape.u = 0.5f; shape.layers = 1; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-128,-64), cpv(-128,144), 2.0f)); + shape.e = 0.0f; shape.u = 0.5f; shape.layers = 1; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-192,80), cpv(-192,176), 2.0f)); + shape.e = 0.0f; shape.u = 0.5f; shape.layers = 1; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-192,176), cpv(-128,240), 2.0f)); + shape.e = 0.0f; shape.u = 0.0f; shape.layers = 1; + shape.layers = NOT_GRABABLE_MASK; + + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-128,144), cpv(192,64), 2.0f)); + shape.e = 0.0f; shape.u = 0.5f; shape.layers = 1; + shape.layers = NOT_GRABABLE_MASK; + + cpVect verts[] = [ + cpv(-30,-80), + cpv(-30, 80), + cpv( 30, 64), + cpv( 30,-80), + ]; + + cpBody *plunger = cpSpaceAddBody(space, cpBodyNew(1.0f, INFINITY)); + plunger.p = cpv(-160,-80); + + shape = cpSpaceAddShape(space, cpPolyShapeNew(plunger, 4, verts.ptr, cpvzero)); + shape.e = 1.0f; shape.u = 0.5f; shape.layers = 1; + + // add balls to hopper + for(int i=0; i<numBalls; i++) + balls[i] = add_ball(cpv(-224 + i,80 + 64*i)); + + // add small gear + cpBody *smallGear = cpSpaceAddBody(space, cpBodyNew(10.0f, cpMomentForCircle(10.0f, 80, 0, cpvzero))); + smallGear.p = cpv(-160,-160); + cpBodySetAngle(smallGear, cast(float)-M_PI_2); + + shape = cpSpaceAddShape(space, cpCircleShapeNew(smallGear, 80.0f, cpvzero)); + shape.layers = 0; + + cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, smallGear, cpv(-160,-160), cpvzero)); + + // add big gear + cpBody *bigGear = cpSpaceAddBody(space, cpBodyNew(40.0f, cpMomentForCircle(40.0f, 160, 0, cpvzero))); + bigGear.p = cpv(80,-160); + cpBodySetAngle(bigGear, cast(float)M_PI_2); + + shape = cpSpaceAddShape(space, cpCircleShapeNew(bigGear, 160.0f, cpvzero)); + shape.layers = 0; + + cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, bigGear, cpv(80,-160), cpvzero)); + + // connect the plunger to the small gear. + cpSpaceAddConstraint(space, cpPinJointNew(smallGear, plunger, cpv(80,0), cpv(0,0))); + // connect the gears. + cpSpaceAddConstraint(space, cpGearJointNew(smallGear, bigGear, -M_PI_2, -2.0f)); + + + // feeder mechanism + cpFloat bottom = -300.0f; + cpFloat top = 32.0f; + cpBody *feeder = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForSegment(1.0f, cpv(-224.0f, bottom), cpv(-224.0f, top)))); + feeder.p = cpv(-224, (bottom + top)/2.0f); + + cpFloat len = top - bottom; + cpSpaceAddShape(space, cpSegmentShapeNew(feeder, cpv(0.0f, len/2.0f), cpv(0.0f, -len/2.0f), 20.0f)); + + cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, feeder, cpv(-224.0f, bottom), cpv(0.0f, -len/2.0f))); + cpVect anchr = cpBodyWorld2Local(feeder, cpv(-224.0f, -160.0f)); + cpSpaceAddConstraint(space, cpPinJointNew(feeder, smallGear, anchr, cpv(0.0f, 80.0f))); + + // motorize the second gear + motor = cpSpaceAddConstraint(space, cpSimpleMotorNew(staticBody, bigGear, 3.0f)); + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Pump = { + "Pump", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/PyramidStack.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,87 @@ + +// written in the D programming language + +module samples.PyramidStack; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +static cpSpace *space; + +static void +update(int ticks) +{ + int steps = 3; + cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + } +} + +static cpSpace * +init() +{ + cpResetShapeIdCounter(); + + space = cpSpaceNew(); + space.iterations = 30; + cpSpaceResizeStaticHash(space, 40.0f, 1000); + cpSpaceResizeActiveHash(space, 40.0f, 1000); + space.gravity = cpv(0, -100); + space.sleepTimeThreshold = 0.5f; + + cpBody *_body; + cpBody *staticBody = &space.staticBody; + cpShape *shape; + + // Create segments around the edge of the screen. + shape = cpSpaceAddShape(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 = cpSpaceAddShape(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 = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + // Add lots of boxes. + for(int i=0; i<14; i++){ + for(int j=0; j<=i; j++){ + _body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForBox(1.0f, 30.0f, 30.0f))); + _body.p = cpv(j*32 - i*16, 300 - i*32); + + shape = cpSpaceAddShape(space, cpBoxShapeNew(_body, 30.0f, 30.0f)); + shape.e = 0.0f; shape.u = 0.8f; + } + } + + // Add a ball to make things more interesting + cpFloat radius = 15.0f; + _body = cpSpaceAddBody(space, cpBodyNew(10.0f, cpMomentForCircle(10.0f, 0.0f, radius, cpvzero))); + _body.p = cpv(0, -240 + radius+5); + + shape = cpSpaceAddShape(space, cpCircleShapeNew(_body, radius, cpvzero)); + shape.e = 0.0f; shape.u = 0.9f; + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo PyramidStack = { + "Pyramid Stack", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/PyramidTopple.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,120 @@ + +// written in the D programming language + +module samples.PyramidTopple; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +import std.math:PI; + +static cpSpace *space; + +static void +update(int ticks) +{ + int steps = 3; + cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++) + cpSpaceStep(space, dt); +} + +static cpSpace * +init() +{ + cpResetShapeIdCounter(); + + space = cpSpaceNew(); + space.iterations = 30; + cpSpaceResizeActiveHash(space, 30.0f, 2999); + cpSpaceResizeStaticHash(space, 30.0f, 999); + space.gravity = cpv(0, -300); + space.sleepTimeThreshold = 0.5f; + + cpBody *_body; + + cpShape *shape; + + // Vertexes for the dominos. + int num = 4; + cpVect verts[] = [ + cpv(-3,-20), + cpv(-3, 20), + cpv( 3, 20), + cpv( 3,-20), + ]; + + // Add a floor. + shape = cpSpaceAddShape(space, cpSegmentShapeNew(&space.staticBody, cpv(-600,-240), cpv(600,-240), 0.0f)); + shape.e = 1.0f; shape.u = 1.0f; + shape.layers = NOT_GRABABLE_MASK; + + // Shared friction constant. + cpFloat u = 0.6f; + + // Add the dominoes. Skim over this. It doesn't do anything fancy, and it's hard to follow. + int n = 9; + for(int i=1; i<=n; i++){ + cpVect offset = cpv(-i*60/2.0f, (n - i)*52); + + for(int j=0; j<i; j++){ + _body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts.ptr, cpvzero))); + _body.p = cpvadd(cpv(j*60, -220), offset); + + shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, num, verts.ptr, cpvzero)); + shape.e = 0.0f; shape.u = u; + + + _body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts.ptr, cpvzero))); + _body.p = cpvadd(cpv(j*60, -197), offset); + cpBodySetAngle(_body, cast(float)PI/2.0f); + + shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, num, verts.ptr, cpvzero)); + shape.e = 0.0f; shape.u = u; + + + if(j == (i - 1)) continue; + _body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts.ptr, cpvzero))); + _body.p = cpvadd(cpv(j*60 + 30, -191), offset); + cpBodySetAngle(_body, cast(float)PI/2.0f); + + shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, num, verts.ptr, cpvzero)); + shape.e = 0.0f; shape.u = u; + } + + _body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts.ptr, cpvzero))); + _body.p = cpvadd(cpv(-17, -174), offset); + + shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, num, verts.ptr, cpvzero)); + shape.e = 0.0f; shape.u = u; + + + _body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForPoly(1.0f, num, verts.ptr, cpvzero))); + _body.p = cpvadd(cpv((i - 1)*60 + 17, -174), offset); + + shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, num, verts.ptr, cpvzero)); + shape.e = 0.0f; shape.u = u; + } + + // Give the last domino a little tap. +// body.w = -1; +// body.v = cpv(-body.w*20, 0); + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo PyramidTopple = { + "Pyramid Topple", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Query.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,136 @@ + +// written in the D programming language + +module samples.Query; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; +import gameApp; + +import std.math; + +//extern cpVect mousePos; + +static cpSpace *space; + +static cpShape *querySeg = null; + + +static void +update(int ticks) +{ + //messageString[0] = '\0'; + + cpVect start = cpvzero; + cpVect end = /*cpv(0, 85);//*/mousePos; + cpVect lineEnd = end; + + //{ + // char infoString[1024]; + // sprintf(infoString, "Query: Dist(%f) Point%s, ", cpvdist(start, end), cpvstr(end)); + // strcat(messageString, infoString); + //} + + cpSegmentQueryInfo info = {}; + if(cpSpaceSegmentQueryFirst(space, start, end, CP_ALL_LAYERS, CP_NO_GROUP, &info)){ + cpVect point = cpSegmentQueryHitPoint(start, end, info); + lineEnd = cpvadd(point, cpvzero);//cpvmult(info.n, 4.0f)); + + //char infoString[1024]; + //sprintf(infoString, "Segment Query: Dist(%f) Normal%s", cpSegmentQueryHitDist(start, end, info), cpvstr(info.n)); + //strcat(messageString, infoString); + } else { + //strcat(messageString, "Segment Query (None)"); + } + + cpSegmentShapeSetEndpoints(querySeg, start, lineEnd); + cpShapeCacheBB(querySeg); // force it to update it's collision detection data so it will draw + + // normal other stuff. + int steps = 1; + cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + } +} + +static cpSpace * +init() +{ + cpResetShapeIdCounter(); + + space = cpSpaceNew(); + space.elasticIterations = 0; + space.iterations = 5; + + cpSpaceResizeStaticHash(space, 40.0f, 999); + cpSpaceResizeActiveHash(space, 30.0f, 2999); + + cpBody *staticBody = &space.staticBody; + cpShape *shape; + + // add a non-collidable segment as a quick and dirty way to draw the query line + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpvzero, cpv(100.0f, 0.0f), 4.0f)); + shape.layers = 0; + querySeg = shape; + + { // add a fat segment + cpFloat mass = 1.0f; + cpFloat length = 100.0f; + cpVect a = cpv(-length/2.0f, 0.0f), b = cpv(length/2.0f, 0.0f); + + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForSegment(mass, a, b))); + _body.p = cpv(0.0f, 100.0f); + + cpSpaceAddShape(space, cpSegmentShapeNew(_body, a, b, 20.0f)); + } + + { // add a static segment + cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(0, 300), cpv(300, 0), 0.0f)); + } + + { // add a pentagon + cpFloat mass = 1.0f; + const int NUM_VERTS = 5; + + cpVect verts[NUM_VERTS]; + for(int i=0; i<NUM_VERTS; i++){ + cpFloat angle = -2*PI*i/(cast(cpFloat) NUM_VERTS); + verts[i] = cpv(30*cos(angle), 30*sin(angle)); + } + + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, NUM_VERTS, verts.ptr, cpvzero))); + _body.p = cpv(50.0f, 50.0f); + + cpSpaceAddShape(space, cpPolyShapeNew(_body, NUM_VERTS, verts.ptr, cpvzero)); + } + + { // add a circle + cpFloat mass = 1.0f; + cpFloat r = 20.0f; + + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, r, cpvzero))); + _body.p = cpv(100.0f, 100.0f); + + cpSpaceAddShape(space, cpCircleShapeNew(_body, r, cpvzero)); + } + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Query = { + "Segment Query", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Sensors.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,142 @@ + +// written in the D programming language + +module samples.Sensors; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +static cpSpace *space; + +enum CollisionTypes { + BALL_TYPE, + BLOCKING_SENSOR_TYPE, + CATCH_SENSOR_TYPE, +}; + +struct Emitter { + int queue; + int blocked; + cpVect position; +} + +static Emitter emitterInstance; + +static cpBool +blockerBegin(cpArbiter *arb, cpSpace *space, void *unused) +{ + mixin(CP_ARBITER_GET_SHAPES!("arb", "a", "b")); + Emitter *emitter = cast(Emitter *) a.data; + + emitter.blocked++; + + return cpFalse; // Return values from sensors callbacks are ignored, +} + +static void +blockerSeparate(cpArbiter *arb, cpSpace *space, void *unused) +{ + mixin(CP_ARBITER_GET_SHAPES!("arb", "a", "b")); + Emitter *emitter = cast(Emitter *)a.data; + + emitter.blocked--; +} + +static void +postStepRemove(cpSpace *space, cpShape *shape, void *unused) +{ + cpSpaceRemoveBody(space, shape._body); + cpSpaceRemoveShape(space, shape); + + cpBodyFree(shape._body); + cpShapeFree(shape); +} + +static cpBool +catcherBarBegin(cpArbiter *arb, cpSpace *space, void *unused) +{ + mixin(CP_ARBITER_GET_SHAPES!("arb", "a", "b")); + Emitter *emitter = cast(Emitter *) a.data; + + emitter.queue++; + cpSpaceAddPostStepCallback(space, cast(cpPostStepFunc)&postStepRemove, b, null); + + return cpFalse; +} + +static cpFloat frand_unit(){return 2.0f*(frand()) - 1.0f;} + +static void +update(int ticks) +{ + int steps = 1; + cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + if(!emitterInstance.blocked && emitterInstance.queue){ + emitterInstance.queue--; + + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(1.0f, cpMomentForCircle(1.0f, 15.0f, 0.0f, cpvzero))); + _body.p = emitterInstance.position; + _body.v = cpvmult(cpv(frand_unit(), frand_unit()), 100.0f); + + cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(_body, 15.0f, cpvzero)); + shape.collision_type = CollisionTypes.BALL_TYPE; + } + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + } +} + +static cpSpace * +init() +{ + cpResetShapeIdCounter(); + + space = cpSpaceNew(); + space.iterations = 10; + space.gravity = cpv(0, -100); + + cpBody *staticBody = &space.staticBody; + cpShape *shape; + + // Data structure for our ball emitter + // We'll use two sensors for it, one to see if the emitter is blocked + // a second to catch the balls and add them back to the emitter + emitterInstance.queue = 5; + emitterInstance.blocked = 0; + emitterInstance.position = cpv(0, 150); + + // Create our blocking sensor, so we know when the emitter is clear to emit another ball + shape = cpSpaceAddShape(space, cpCircleShapeNew(staticBody, 15.0f, emitterInstance.position)); + shape.sensor = 1; + shape.collision_type = CollisionTypes.BLOCKING_SENSOR_TYPE; + shape.data = &emitterInstance; + + // Create our catch sensor to requeue the balls when they reach the bottom of the screen + shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-2000, -200), cpv(2000, -200), 15.0f)); + shape.sensor = 1; + shape.collision_type = CollisionTypes.CATCH_SENSOR_TYPE; + shape.data = &emitterInstance; + + cpSpaceAddCollisionHandler(space, CollisionTypes.BLOCKING_SENSOR_TYPE, CollisionTypes.BALL_TYPE, &blockerBegin, null, null, &blockerSeparate, null); + cpSpaceAddCollisionHandler(space, CollisionTypes.CATCH_SENSOR_TYPE, CollisionTypes.BALL_TYPE, &catcherBarBegin, null, null, null, null); + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Sensors = { + "Sensors", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Simple.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,89 @@ + +// written in the D programming language + +module samples.Simple; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +static cpSpace *space; + +// Init is called by the demo code to set up the demo. +static cpSpace * +init() +{ + // Create a space, a space is a simulation world. It simulates the motions of rigid bodies, + // handles collisions between them, and simulates the joints between them. + space = cpSpaceNew(); + + // Lets set some parameters of the space: + // More iterations make the simulation more accurate but slower + space.iterations = 10; + // These parameters tune the efficiency of the collision detection. + // For more info: http://code.google.com/p/chipmunk-physics/wiki/cpSpace + cpSpaceResizeStaticHash(space, 30.0f, 1000); + cpSpaceResizeActiveHash(space, 30.0f, 1000); + // Give it some gravity + space.gravity = cpv(0, -100); + + // Create A ground segment along the bottom of the screen + // By attaching it to &space.staticBody instead of a body, we make it a static shape. + cpShape *ground = cpSegmentShapeNew(&space.staticBody, cpv(-320,-240), cpv(320,-240), 0.0f); + // Set some parameters of the shape. + // For more info: http://code.google.com/p/chipmunk-physics/wiki/cpShape + ground.e = 1.0f; ground.u = 1.0f; + ground.layers = NOT_GRABABLE_MASK; // Used by the Demo mouse grabbing code + // Add the shape to the space as a static shape + // If a shape never changes position, add it as static so Chipmunk knows it only needs to + // calculate collision information for it once when it is added. + // Do not change the postion of a static shape after adding it. + cpSpaceAddShape(space, ground); + + // Add a moving circle object. + cpFloat radius = 15.0f; + cpFloat mass = 10.0f; + // This time we need to give a mass and moment of inertia when creating the circle. + cpBody *ballBody = cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero)); + // Set some parameters of the body: + // For more info: http://code.google.com/p/chipmunk-physics/wiki/cpBody + ballBody.p = cpv(0, -100 + radius+50); + ballBody.v = cpv(0, -20); + // Add the body to the space so it will be simulated and move around. + cpSpaceAddBody(space, ballBody); + + + // Add a circle shape for the ball. + // Shapes are always defined relative to the center of gravity of the body they are attached to. + // When the body moves or rotates, the shape will move with it. + // Additionally, all of the cpSpaceAdd*() functions return the thing they added so you can create and add in one go. + cpShape *ballShape = cpSpaceAddShape(space, cpCircleShapeNew(ballBody, radius, cpvzero)); + ballShape.e = 0.0f; ballShape.u = 0.9f; + + return space; +} + +// Update is called by the demo code each frame. +static void +update(int ticks) +{ + // Chipmunk allows you to use a different timestep each frame, but it works much better when you use a fixed timestep. + // An excellent article on why fixed timesteps for game logic can be found here: http://gafferongames.com/game-physics/fix-your-timestep/ + cpSpaceStep(space, 1.0f/60.0f); +} + +// destroy is called by the demo code to free all the memory we've allocated +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Simple = { + "Simple", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Springies.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,151 @@ + +// written in the D programming language + +module samples.Springies; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +static cpSpace *space; + +static cpFloat +springForce(cpConstraint *spring, cpFloat dist) +{ + cpFloat clamp = 20.0f; + return cpfclamp(cpDampedSpringGetRestLength(spring) - dist, -clamp, clamp)*cpDampedSpringGetStiffness(spring); +} + +static cpConstraint * +new_spring(cpBody *a, cpBody *b, cpVect anchr1, cpVect anchr2, cpFloat restLength, cpFloat stiff, cpFloat damp) +{ + cpConstraint *spring = cpDampedSpringNew(a, b, anchr1, anchr2, restLength, stiff, damp); + cpDampedSpringSetSpringForceFunc(spring, &springForce); + + return spring; +} + +static void +update(int ticks) +{ + enum int steps = 1; + enum cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + } +} + +static cpBody * +add_bar(cpVect a, cpVect b, int group) +{ + cpVect center = cpvmult(cpvadd(a, b), 1.0f/2.0f); + cpFloat length = cpvlength(cpvsub(b, a)); + cpFloat mass = length/160.0f; + + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, mass*length*length/12.0f)); + _body.p = center; + + cpShape *shape = cpSpaceAddShape(space, cpSegmentShapeNew(_body, cpvsub(a, center), cpvsub(b, center), 10.0f)); + shape.group = group; + + return _body; +} + +static cpSpace * +init() +{ + space = cpSpaceNew(); + cpBody *staticBody = &space.staticBody; + + cpBody *body1 = add_bar(cpv(-240, 160), cpv(-160, 80), 1); + cpBody *body2 = add_bar(cpv(-160, 80), cpv( -80, 160), 1); + cpBody *body3 = add_bar(cpv( 0, 160), cpv( 80, 0), 0); + cpBody *body4 = add_bar(cpv( 160, 160), cpv( 240, 160), 0); + cpBody *body5 = add_bar(cpv(-240, 0), cpv(-160, -80), 2); + cpBody *body6 = add_bar(cpv(-160, -80), cpv( -80, 0), 2); + cpBody *body7 = add_bar(cpv( -80, 0), cpv( 0, 0), 2); + cpBody *body8 = add_bar(cpv( 0, -80), cpv( 80, -80), 0); + cpBody *body9 = add_bar(cpv( 240, 80), cpv( 160, 0), 3); + cpBody *body10 = add_bar(cpv( 160, 0), cpv( 240, -80), 3); + cpBody *body11 = add_bar(cpv(-240, -80), cpv(-160, -160), 4); + cpBody *body12 = add_bar(cpv(-160, -160), cpv( -80, -160), 0); + cpBody *body13 = add_bar(cpv( 0, -160), cpv( 80, -160), 0); + cpBody *body14 = add_bar(cpv( 160, -160), cpv( 240, -160), 0); + + cpSpaceAddConstraint(space, cpPivotJointNew2( body1, body2, cpv( 40,-40), cpv(-40,-40))); + cpSpaceAddConstraint(space, cpPivotJointNew2( body5, body6, cpv( 40,-40), cpv(-40,-40))); + cpSpaceAddConstraint(space, cpPivotJointNew2( body6, body7, cpv( 40, 40), cpv(-40, 0))); + cpSpaceAddConstraint(space, cpPivotJointNew2( body9, body10, cpv(-40,-40), cpv(-40, 40))); + cpSpaceAddConstraint(space, cpPivotJointNew2(body11, body12, cpv( 40,-40), cpv(-40, 0))); + + cpFloat stiff = 100.0f; + cpFloat damp = 0.5f; + cpSpaceAddConstraint(space, new_spring(staticBody, body1, cpv(-320, 240), cpv(-40, 40), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(staticBody, body1, cpv(-320, 80), cpv(-40, 40), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(staticBody, body1, cpv(-160, 240), cpv(-40, 40), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring(staticBody, body2, cpv(-160, 240), cpv( 40, 40), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(staticBody, body2, cpv( 0, 240), cpv( 40, 40), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring(staticBody, body3, cpv( 80, 240), cpv(-40, 80), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring(staticBody, body4, cpv( 80, 240), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(staticBody, body4, cpv( 320, 240), cpv( 40, 0), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring(staticBody, body5, cpv(-320, 80), cpv(-40, 40), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring(staticBody, body9, cpv( 320, 80), cpv( 40, 40), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring(staticBody, body10, cpv( 320, 0), cpv( 40,-40), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(staticBody, body10, cpv( 320,-160), cpv( 40,-40), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring(staticBody, body11, cpv(-320,-160), cpv(-40, 40), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring(staticBody, body12, cpv(-240,-240), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(staticBody, body12, cpv( 0,-240), cpv( 40, 0), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring(staticBody, body13, cpv( 0,-240), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(staticBody, body13, cpv( 80,-240), cpv( 40, 0), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring(staticBody, body14, cpv( 80,-240), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(staticBody, body14, cpv( 240,-240), cpv( 40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(staticBody, body14, cpv( 320,-160), cpv( 40, 0), 0.0f, stiff, damp)); + + cpSpaceAddConstraint(space, new_spring( body1, body5, cpv( 40,-40), cpv(-40, 40), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body1, body6, cpv( 40,-40), cpv( 40, 40), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body2, body3, cpv( 40, 40), cpv(-40, 80), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body3, body4, cpv(-40, 80), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body3, body4, cpv( 40,-80), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body3, body7, cpv( 40,-80), cpv( 40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body3, body7, cpv(-40, 80), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body3, body8, cpv( 40,-80), cpv( 40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body3, body9, cpv( 40,-80), cpv(-40,-40), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body4, body9, cpv( 40, 0), cpv( 40, 40), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body5, body11, cpv(-40, 40), cpv(-40, 40), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body5, body11, cpv( 40,-40), cpv( 40,-40), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body7, body8, cpv( 40, 0), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body8, body12, cpv(-40, 0), cpv( 40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body8, body13, cpv(-40, 0), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body8, body13, cpv( 40, 0), cpv( 40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring( body8, body14, cpv( 40, 0), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(body10, body14, cpv( 40,-40), cpv(-40, 0), 0.0f, stiff, damp)); + cpSpaceAddConstraint(space, new_spring(body10, body14, cpv( 40,-40), cpv(-40, 0), 0.0f, stiff, damp)); + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Springies = { + "Springies", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Tank.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,134 @@ + +// written in the D programming language + +module samples.Tank; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +import gameApp; + +static cpSpace *space; + +static cpBody *tankBody; +static cpBody *tankControlBody; + +static void +update(int ticks) +{ + enum int steps = 1; + enum cpFloat dt = 1.0f/60.0f/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + // turn the control _body based on the angle relative to the actual _body + cpVect mouseDelta = cpvsub(mousePos, tankBody.p); + cpFloat turn = cpvtoangle(cpvunrotate(tankBody.rot, mouseDelta)); + cpBodySetAngle(tankControlBody, tankBody.a - turn); + + // drive the tank towards the mouse + if(cpvnear(mousePos, tankBody.p, 30.0)){ + tankControlBody.v = cpvzero; // stop + } else { + cpFloat direction = (cpvdot(mouseDelta, tankBody.rot) > 0.0 ? 1.0 : -1.0); + tankControlBody.v = cpvrotate(tankBody.rot, cpv(30.0f*direction, 0.0f)); + } + + cpSpaceStep(space, dt); + } +} + +static cpBody * +add_box(cpFloat size, cpFloat mass) +{ + cpVect verts[] = [ + cpv(-size,-size), + cpv(-size, size), + cpv( size, size), + cpv( size,-size), + ]; + + cpFloat radius = cpvlength(cpv(size, size)); + + cpBody *_body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForPoly(mass, 4, verts.ptr, cpvzero))); + _body.p = cpv(frand()*(640 - 2*radius) - (320 - radius), frand()*(480 - 2*radius) - (240 - radius)); + + cpShape *shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, 4, verts.ptr, cpvzero)); + shape.e = 0.0f; shape.u = 0.7f; + + return _body; +} + +static cpSpace * +init() +{ + cpResetShapeIdCounter(); + + space = cpSpaceNew(); + cpSpaceResizeActiveHash(space, 30.0f, 1000); + space.iterations = 10; + space.sleepTimeThreshold = 0.5f; + + cpBody *staticBody = &space.staticBody; + cpShape *shape; + + // Create segments around the edge of the screen. + shape = cpSpaceAddShape(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 = cpSpaceAddShape(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 = cpSpaceAddShape(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 = cpSpaceAddShape(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<50; i++){ + cpBody *_body = add_box(10.0, 1.0); + + cpConstraint *pivot = cpSpaceAddConstraint(space, cpPivotJointNew2(staticBody, _body, cpvzero, cpvzero)); + pivot.biasCoef = 0.0f; // disable joint correction + pivot.maxForce = 1000.0f; // emulate linear friction + + cpConstraint *gear = cpSpaceAddConstraint(space, cpGearJointNew(staticBody, _body, 0.0f, 1.0f)); + gear.biasCoef = 0.0f; // disable joint correction + gear.maxForce = 5000.0f; // emulate angular friction + } + + // We joint the tank to the control _body and control the tank indirectly by modifying the control _body. + tankControlBody = cpBodyNew(INFINITY, INFINITY); + tankBody = add_box(15.0, 10.0); + + cpConstraint *pivot = cpSpaceAddConstraint(space, cpPivotJointNew2(tankControlBody, tankBody, cpvzero, cpvzero)); + pivot.biasCoef = 0.0f; // disable joint correction + pivot.maxForce = 10000.0f; // emulate linear friction + + cpConstraint *gear = cpSpaceAddConstraint(space, cpGearJointNew(tankControlBody, tankBody, 0.0f, 1.0f)); + gear.biasCoef = 1.0f; // limit angular correction rate + gear.maxBias = 1.0f; // limit angular correction rate + gear.maxForce = 500000.0f; // emulate angular friction + + return space; +} + +static void +destroy() +{ + cpBodyFree(tankControlBody); + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Tank = { + "Tank", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/TheoJansen.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,161 @@ + +// written in the D programming language + +module samples.TheoJansen; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +import gameApp; + +import std.math; + +enum M_PI = PI; +enum M_PI_2 = PI*0.5f; + +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; + + enum int steps = 3; + enum cpFloat dt = 1.0f/60.0f/cast(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() +{ + 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(cast(cpFloat)(2*i+0)/cast(cpFloat)num_legs*M_PI), crank_radius)); + make_leg(side, -offset, chassis, crank, cpvmult(cpvforangle(cast(cpFloat)(2*i+1)/cast(cpFloat)num_legs*M_PI), crank_radius)); + } + + motor = cpSimpleMotorNew(chassis, crank, 6.0f); + cpSpaceAddConstraint(space, motor); + + return space; +} + +static void +destroy() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo TheoJansen = { + "Theo Jansen Machine", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/Tumble.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,117 @@ + +// written in the D programming language + +module samples.Tumble; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +static cpSpace *space; +static cpBody *staticBody; + +static void +update(int ticks) +{ + enum int steps = 3; + enum cpFloat dt = 1.0f/60.0f/cast(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() +{ + 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; + + int foo; + // 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.ptr, cpvzero))); + _body.p = cpv(i*60 - 150, j*30 - 150); + + //BUG: crazy fucking dmd codegen bug when optimizing (2.050) + foo = i+j; + + shape = cpSpaceAddShape(space, cpPolyShapeNew(_body, num, verts.ptr, cpvzero)); + shape.e = 0.0f; shape.u = 0.7f; + } + } + + return space; +} + +static void +destroy() +{ + cpBodyFree(staticBody); + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo Tumble = { + "Tumble", + null, + &init, + &update, + &destroy, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/trunk/tests/ChipmunkDemos/samples/UnsafeOps.d Sat Dec 04 02:02:29 2010 +0100 @@ -0,0 +1,98 @@ + +// written in the D programming language + +module samples.UnsafeOps; + +import chipmunkd.chipmunk; + +import samples.ChipmunkDemo; + +import gameApp; + +import std.math; + +static cpSpace *space; + +enum M_PI = PI; +enum M_PI_2 = PI*0.5f; + +enum 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/cast(cpFloat)steps; + + for(int i=0; i<steps; i++){ + cpSpaceStep(space, dt); + } +} + +static cpSpace * +init() +{ + 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() +{ + cpSpaceFreeChildren(space); + cpSpaceFree(space); +} + +chipmunkDemo UnsafeOps = { + "Unsafe Operations", + null, + &init, + &update, + &destroy, +};