Mercurial > projects > chipmunkd
diff trunk/tests/ChipmunkDemos/drawSpace.d @ 16:af2f61a96318
ported chipmunk demos
author | Extrawurst |
---|---|
date | Sat, 04 Dec 2010 02:02:29 +0100 |
parents | |
children | f897d96cc7c9 |
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(); + } +}