static void cpMarchCellHard( cpFloat t, cpFloat a, cpFloat b, cpFloat c, cpFloat d, cpFloat x0, cpFloat x1, cpFloat y0, cpFloat y1, cpMarchSegmentFunc segment, void *segment_data ){ // midpoints cpFloat xm = cpflerp(x0, x1, 0.5f); cpFloat ym = cpflerp(y0, y1, 0.5f); switch((a>t)<<0 | (b>t)<<1 | (c>t)<<2 | (d>t)<<3){ case 0x1: segs(cpv(x0, ym), cpv(xm, ym), cpv(xm, y0), segment, segment_data); break; case 0x2: segs(cpv(xm, y0), cpv(xm, ym), cpv(x1, ym), segment, segment_data); break; case 0x3: seg(cpv(x0, ym), cpv(x1, ym), segment, segment_data); break; case 0x4: segs(cpv(xm, y1), cpv(xm, ym), cpv(x0, ym), segment, segment_data); break; case 0x5: seg(cpv(xm, y1), cpv(xm, y0), segment, segment_data); break; case 0x6: segs(cpv(xm, y0), cpv(xm, ym), cpv(x0, ym), segment, segment_data); segs(cpv(xm, y1), cpv(xm, ym), cpv(x1, ym), segment, segment_data); break; case 0x7: segs(cpv(xm, y1), cpv(xm, ym), cpv(x1, ym), segment, segment_data); break; case 0x8: segs(cpv(x1, ym), cpv(xm, ym), cpv(xm, y1), segment, segment_data); break; case 0x9: segs(cpv(x1, ym), cpv(xm, ym), cpv(xm, y0), segment, segment_data); segs(cpv(x0, ym), cpv(xm, ym), cpv(xm, y1), segment, segment_data); break; case 0xA: seg(cpv(xm, y0), cpv(xm, y1), segment, segment_data); break; case 0xB: segs(cpv(x0, ym), cpv(xm, ym), cpv(xm, y1), segment, segment_data); break; case 0xC: seg(cpv(x1, ym), cpv(x0, ym), segment, segment_data); break; case 0xD: segs(cpv(x1, ym), cpv(xm, ym), cpv(xm, y0), segment, segment_data); break; case 0xE: segs(cpv(xm, y0), cpv(xm, ym), cpv(x0, ym), segment, segment_data); break; default: break; // 0x0 and 0xF } }
static cpSpace * init(void) { ChipmunkDemoMessageString = "Sticky collisions using the cpArbiter data pointer."; cpSpace *space = cpSpaceNew(); cpSpaceSetIterations(space, 10); cpSpaceSetGravity(space, cpv(0, -1000)); cpSpaceSetCollisionSlop(space, 2.0); cpBody *staticBody = cpSpaceGetStaticBody(space); cpShape *shape; // Create segments around the edge of the screen. shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-340,-260), cpv(-340, 260), 20.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetCollisionType(shape, COLLIDE_STICK_SENSOR); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv( 340,-260), cpv( 340, 260), 20.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetCollisionType(shape, COLLIDE_STICK_SENSOR); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-340,-260), cpv( 340,-260), 20.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetCollisionType(shape, COLLIDE_STICK_SENSOR); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); shape = cpSpaceAddShape(space, cpSegmentShapeNew(staticBody, cpv(-340, 260), cpv( 340, 260), 20.0f)); cpShapeSetElasticity(shape, 1.0f); cpShapeSetFriction(shape, 1.0f); cpShapeSetCollisionType(shape, COLLIDE_STICK_SENSOR); cpShapeSetLayers(shape, NOT_GRABABLE_MASK); for(int i=0; i<200; i++){ cpFloat mass = 0.15f; cpFloat radius = 10.0f; cpBody *body = cpSpaceAddBody(space, cpBodyNew(mass, cpMomentForCircle(mass, 0.0f, radius, cpvzero))); cpBodySetPos(body, cpv(cpflerp(-150.0f, 150.0f, frand()), cpflerp(-150.0f, 150.0f, frand()))); cpShape *shape = cpSpaceAddShape(space, cpCircleShapeNew(body, radius + STICK_SENSOR_THICKNESS, cpvzero)); cpShapeSetFriction(shape, 0.9f); cpShapeSetCollisionType(shape, COLLIDE_STICK_SENSOR); } cpSpaceAddCollisionHandler(space, COLLIDE_STICK_SENSOR, COLLIDE_STICK_SENSOR, NULL, StickyPreSolve, NULL, StickySeparate, NULL); return space; }
// The looping and sample caching code is shared between cpMarchHard() and cpMarchSoft(). static void cpMarchCells( cpBB bb, unsigned long x_samples, unsigned long y_samples, cpFloat t, cpMarchSegmentFunc segment, void *segment_data, cpMarchSampleFunc sample, void *sample_data, cpMarchCellFunc cell ){ cpFloat x_denom = 1.0/(cpFloat)(x_samples - 1); cpFloat y_denom = 1.0/(cpFloat)(y_samples - 1); // TODO range assertions and short circuit for 0 sized windows. // Keep a copy of the previous row to avoid double lookups. cpFloat *buffer = (cpFloat *)cpcalloc(x_samples, sizeof(cpFloat)); for(unsigned long i=0; i<x_samples; i++) buffer[i] = sample(cpv(cpflerp(bb.l, bb.r, i*x_denom), bb.b), sample_data); for(unsigned long j=0; j<y_samples-1; j++){ cpFloat y0 = cpflerp(bb.b, bb.t, (j+0)*y_denom); cpFloat y1 = cpflerp(bb.b, bb.t, (j+1)*y_denom); cpFloat a, b = buffer[0]; cpFloat c, d = sample(cpv(bb.l, y1), sample_data); buffer[0] = d; for(unsigned long i=0; i<x_samples-1; i++){ cpFloat x0 = cpflerp(bb.l, bb.r, (i+0)*x_denom); cpFloat x1 = cpflerp(bb.l, bb.r, (i+1)*x_denom); a = b, b = buffer[i + 1]; c = d, d = sample(cpv(x1, y1), sample_data); buffer[i + 1] = d; cell(t, a, b, c, d, x0, x1, y0, y1, segment, segment_data); } } cpfree(buffer); }
static void DrawShape(cpShape *shape, DrawNode *renderer) { cpBody *body = cpShapeGetBody(shape); Color4F color = ColorForBody(body); switch (shape->CP_PRIVATE(klass)->type) { case CP_CIRCLE_SHAPE: { cpCircleShape *circle = (cpCircleShape *)shape; cpVect center = circle->tc; cpFloat radius = circle->r; renderer->drawDot(cpVert2Point(center), cpfmax(radius, 1.0), color); renderer->drawSegment(cpVert2Point(center), cpVert2Point(cpvadd(center, cpvmult(cpBodyGetRotation(body), radius))), 1.0, color); } break; case CP_SEGMENT_SHAPE: { cpSegmentShape *seg = (cpSegmentShape *)shape; renderer->drawSegment(cpVert2Point(seg->ta), cpVert2Point(seg->tb), cpfmax(seg->r, 2.0), color); } break; case CP_POLY_SHAPE: { cpPolyShape* poly = (cpPolyShape*)shape; Color4F line = color; line.a = cpflerp(color.a, 1.0, 0.5); int num = poly->count; Vec2* pPoints = new (std::nothrow) Vec2[num]; for(int i=0;i<num;++i) pPoints[i] = cpVert2Point(poly->planes[i].v0); renderer->drawPolygon(pPoints, num, color, 1.0, line); CC_SAFE_DELETE_ARRAY(pPoints); } break; default: cpAssertHard(false, "Bad assertion in DrawShape()"); } }
static void DrawShape(cpShape *shape, DrawNode *renderer) { cpBody *body = shape->body; Color4F color = ColorForBody(body); switch (shape->CP_PRIVATE(klass)->type) { case CP_CIRCLE_SHAPE: { cpCircleShape *circle = (cpCircleShape *)shape; cpVect center = circle->tc; cpFloat radius = circle->r; renderer->drawDot(cpVert2Point(center), cpfmax(radius, 1.0), color); renderer->drawSegment(cpVert2Point(center), cpVert2Point(cpvadd(center, cpvmult(body->rot, radius))), 1.0, color); } break; case CP_SEGMENT_SHAPE: { cpSegmentShape *seg = (cpSegmentShape *)shape; renderer->drawSegment(cpVert2Point(seg->ta), cpVert2Point(seg->tb), cpfmax(seg->r, 2.0), color); } break; case CP_POLY_SHAPE: { cpPolyShape *poly = (cpPolyShape *)shape; Color4F line = color; line.a = cpflerp(color.a, 1.0, 0.5); Vec2* pPoints = cpVertArray2ccpArrayN(poly->tVerts, poly->numVerts); renderer->drawPolygon(pPoints, poly->numVerts, color, 1.0, line); CC_SAFE_DELETE_ARRAY(pPoints); } break; default: cpAssertHard(false, "Bad assertion in DrawShape()"); } }
// Lerps between two positions based on their sample values. static inline cpFloat midlerp(cpFloat x0, cpFloat x1, cpFloat s0, cpFloat s1, cpFloat t) { return cpflerp(x0, x1, (t - s0)/(s1 - s0)); }
static VALUE rb_cpflerp(VALUE self, VALUE f1, VALUE f2, VALUE t) { cpFloat result = cpflerp(NUM2DBL(f1), NUM2DBL(f2), NUM2DBL(t)); return rb_float_new(result); }