void draw_shape(cpBody* body, cpShape* shape, void* data) { // get body info cpVect v = cpBodyGetPos(body); cpFloat angle = cpBodyGetAngle(body); cpVect rot = cpvforangle(angle); // get vectors int n = cpPolyShapeGetNumVerts(shape); SDL_Point* pts = calloc(sizeof(SDL_Point), n+1); // rotate vectors int i; for(i=0; i<n; i++) { cpVect p = cpPolyShapeGetVert(shape, i); cpVect vr = cpvrotate(cpv(p.x,p.y), rot); pts[i] = (SDL_Point) { (vr.x+v.x)*10+50, (vr.y+v.y)*10+50 }; if(i == 0) pts[n] = pts[i]; } // draw SDL_RenderDrawLines(ren, pts, n+1); free(pts); }
void PhysicsShapePolygon::updateScale() { cpFloat factorX = _newScaleX / _scaleX; cpFloat factorY = _newScaleY / _scaleY; auto shape = _cpShapes.front(); int count = cpPolyShapeGetCount(shape); cpVect* vects = new cpVect[count]; for(int i=0;i<count;++i) vects[i] = cpPolyShapeGetVert(shape, i); for (int i = 0; i < count; ++i) { vects[i].x *= factorX; vects[i].y *= factorY; } // convert hole to clockwise if (factorX * factorY < 0) { for (int i = 0; i < count / 2; ++i) { cpVect v = vects[i]; vects[i] = vects[count - i - 1]; vects[count - i - 1] = v; } } cpPolyShapeSetVertsRaw(shape, count, vects); CC_SAFE_DELETE_ARRAY(vects); PhysicsShape::updateScale(); }
static void draw_poly_shape(struct draw_options opts, cpShape *shape, cpBody *body) { int num_verts = cpPolyShapeGetNumVerts(shape); cpVect first_vert = cpBodyLocal2World(body, cpPolyShapeGetVert(shape, 0)); cpVect prev_vert = first_vert; cpVect pos = cpBodyGetPos(body); for (int i = 1; i < num_verts; i++) { cpVect vert = cpBodyLocal2World(body, cpPolyShapeGetVert(shape, i)); draw_line(opts, prev_vert, vert); prev_vert = vert; } /* close up the polygon */ draw_line(opts, prev_vert, first_vert); }
void PhysicsShapePolygon::getPoints(Vec2* outPoints) const { auto shape = _cpShapes.front(); int count = cpPolyShapeGetCount(shape); cpVect* vecs = new cpVect[count]; for(int i=0;i<count;++i) vecs[i] = cpPolyShapeGetVert(shape, i); PhysicsHelper::cpvs2points(vecs, outPoints, count); CC_SAFE_DELETE_ARRAY(vecs); }
void Slice::ClipPoly(cpSpace *space, cpShape *shape, cpVect n, cpFloat dist) { cpBody *body = cpShapeGetBody(shape); int count = cpPolyShapeGetCount(shape); int clippedCount = 0; cpVect *clipped = (cpVect *)alloca((count + 1)*sizeof(cpVect)); for(int i=0, j=count-1; i<count; j=i, i++){ cpVect a = cpBodyLocalToWorld(body, cpPolyShapeGetVert(shape, j)); cpFloat a_dist = cpvdot(a, n) - dist; if(a_dist < 0.0){ clipped[clippedCount] = a; clippedCount++; } cpVect b = cpBodyLocalToWorld(body, cpPolyShapeGetVert(shape, i)); cpFloat b_dist = cpvdot(b, n) - dist; if(a_dist*b_dist < 0.0f){ cpFloat t = cpfabs(a_dist)/(cpfabs(a_dist) + cpfabs(b_dist)); clipped[clippedCount] = cpvlerp(a, b, t); clippedCount++; } } cpVect centroid = cpCentroidForPoly(clippedCount, clipped); cpFloat mass = cpAreaForPoly(clippedCount, clipped, 0.0f)*DENSITY; cpFloat moment = cpMomentForPoly(mass, clippedCount, clipped, cpvneg(centroid), 0.0f); cpBody *new_body = cpSpaceAddBody(space, cpBodyNew(mass, moment)); cpBodySetPosition(new_body, centroid); cpBodySetVelocity(new_body, cpBodyGetVelocityAtWorldPoint(body, centroid)); cpBodySetAngularVelocity(new_body, cpBodyGetAngularVelocity(body)); cpTransform transform = cpTransformTranslate(cpvneg(centroid)); cpShape *new_shape = cpSpaceAddShape(space, cpPolyShapeNew(new_body, clippedCount, clipped, transform, 0.0)); // Copy whatever properties you have set on the original shape that are important cpShapeSetFriction(new_shape, cpShapeGetFriction(shape)); }
float PhysicsShapePolygon::calculateArea() { auto shape = _cpShapes.front(); int count = cpPolyShapeGetCount(shape); cpVect* vecs = new cpVect[count]; for(int i=0;i<count;++i) vecs[i] = cpPolyShapeGetVert(shape, i); float area = PhysicsHelper::cpfloat2float(cpAreaForPoly(count, vecs, cpPolyShapeGetRadius(shape))); CC_SAFE_DELETE_ARRAY(vecs); return area; }
Vec2 PhysicsShapePolygon::getCenter() { auto shape = _cpShapes.front(); int count = cpPolyShapeGetCount(shape); cpVect* vecs = new cpVect[count]; for(int i=0;i<count;++i) vecs[i] = cpPolyShapeGetVert(shape, i); Vec2 center = PhysicsHelper::cpv2point(cpCentroidForPoly(count, vecs)); CC_SAFE_DELETE_ARRAY(vecs); return center; }
float PhysicsShapePolygon::calculateDefaultMoment() { if(_mass == PHYSICS_INFINITY) { return PHYSICS_INFINITY; } else { auto shape = _cpShapes.front(); int count = cpPolyShapeGetCount(shape); cpVect* vecs = new cpVect[count]; for(int i=0;i<count;++i) vecs[i] = cpPolyShapeGetVert(shape, i); float moment = PhysicsHelper::cpfloat2float(cpMomentForPoly(_mass, count, vecs, cpvzero, cpPolyShapeGetRadius(shape))); CC_SAFE_DELETE_ARRAY(vecs); return moment; } }
static void update(cpSpace *space) { cpFloat tolerance = 2.0; if(ChipmunkDemoRightClick && cpShapeNearestPointQuery(shape, ChipmunkDemoMouse, NULL) > tolerance){ cpBody *body = cpShapeGetBody(shape); int count = cpPolyShapeGetNumVerts(shape); // Allocate the space for the new vertexes on the stack. cpVect *verts = (cpVect *)alloca((count + 1)*sizeof(cpVect)); for(int i=0; i<count; i++){ verts[i] = cpPolyShapeGetVert(shape, i); } verts[count] = cpBodyWorld2Local(body, ChipmunkDemoMouse); // This function builds a convex hull for the vertexes. // Because the result array is NULL, it will reduce the input array instead. int hullCount = cpConvexHull(count + 1, verts, NULL, NULL, tolerance); // Figure out how much to shift the body by. cpVect centroid = cpCentroidForPoly(hullCount, verts); // Recalculate the body properties to match the updated shape. cpFloat mass = cpAreaForPoly(hullCount, verts)*DENSITY; cpBodySetMass(body, mass); cpBodySetMoment(body, cpMomentForPoly(mass, hullCount, verts, cpvneg(centroid))); cpBodySetPos(body, cpBodyLocal2World(body, centroid)); // Use the setter function from chipmunk_unsafe.h. // You could also remove and recreate the shape if you wanted. cpPolyShapeSetVerts(shape, hullCount, verts, cpvneg(centroid)); } int steps = 1; cpFloat dt = 1.0f/60.0f/(cpFloat)steps; for(int i=0; i<steps; i++){ cpSpaceStep(space, dt); } }
Vec2 PhysicsShapePolygon::getPoint(int i) const { return PhysicsHelper::cpv2point(cpPolyShapeGetVert(_cpShapes.front(), i)); }
Size PhysicsShapeBox::getSize() const { cpShape* shape = _cpShapes.front(); return PhysicsHelper::cpv2size(cpv(cpvdist(cpPolyShapeGetVert(shape, 1), cpPolyShapeGetVert(shape, 2)), cpvdist(cpPolyShapeGetVert(shape, 0), cpPolyShapeGetVert(shape, 1)))); }
Point PhysicsShapePolygon::getPoint(int i) const { return PhysicsHelper::cpv2point(cpPolyShapeGetVert(_info->getShapes().front(), i)); }
static int cpPolyShape_getVert (lua_State *L) { cpPolyShape *ps = check_cpPolyShape(L, 1); int i = luaL_checkint(L, 2); push_cpVect(L, cpPolyShapeGetVert((cpShape*)ps, i-1)); return 2; }
cpBool Buoyancy::WaterPreSolve(cpArbiter *arb, cpSpace *space, void *ptr) { CP_ARBITER_GET_SHAPES(arb, water, poly); cpBody *body = cpShapeGetBody(poly); // Get the top of the water sensor bounding box to use as the water level. cpFloat level = cpShapeGetBB(water).t; // Clip the polygon against the water level int count = cpPolyShapeGetCount(poly); int clippedCount = 0; #ifdef _MSC_VER // MSVC is pretty much the only compiler in existence that doesn't support variable sized arrays. cpVect clipped[10]; #else cpVect clipped[count + 1]; #endif for(int i=0, j=count-1; i<count; j=i, i++){ cpVect a = cpBodyLocalToWorld(body, cpPolyShapeGetVert(poly, j)); cpVect b = cpBodyLocalToWorld(body, cpPolyShapeGetVert(poly, i)); if(a.y < level){ clipped[clippedCount] = a; clippedCount++; } cpFloat a_level = a.y - level; cpFloat b_level = b.y - level; if(a_level*b_level < 0.0f){ cpFloat t = cpfabs(a_level)/(cpfabs(a_level) + cpfabs(b_level)); clipped[clippedCount] = cpvlerp(a, b, t); clippedCount++; } } // Calculate buoyancy from the clipped polygon area cpFloat clippedArea = cpAreaForPoly(clippedCount, clipped, 0.0f); cpFloat displacedMass = clippedArea*FLUID_DENSITY; cpVect centroid = cpCentroidForPoly(clippedCount, clipped); cpDataPointer data = ptr; DrawPolygon(clippedCount, clipped, 0.0f, RGBAColor(0, 0, 1, 1), RGBAColor(0, 0, 1, 0.1f), data); DrawDot(5, centroid, RGBAColor(0, 0, 1, 1), data); cpFloat dt = cpSpaceGetCurrentTimeStep(space); cpVect g = cpSpaceGetGravity(space); // Apply the buoyancy force as an impulse. cpBodyApplyImpulseAtWorldPoint(body, cpvmult(g, -displacedMass*dt), centroid); // Apply linear damping for the fluid drag. cpVect v_centroid = cpBodyGetVelocityAtWorldPoint(body, centroid); cpFloat k = k_scalar_body(body, centroid, cpvnormalize(v_centroid)); cpFloat damping = clippedArea*FLUID_DRAG*FLUID_DENSITY; cpFloat v_coef = cpfexp(-damping*dt*k); // linear drag // cpFloat v_coef = 1.0/(1.0 + damping*dt*cpvlength(v_centroid)*k); // quadratic drag cpBodyApplyImpulseAtWorldPoint(body, cpvmult(cpvsub(cpvmult(v_centroid, v_coef), v_centroid), 1.0/k), centroid); // Apply angular damping for the fluid drag. cpVect cog = cpBodyLocalToWorld(body, cpBodyGetCenterOfGravity(body)); cpFloat w_damping = cpMomentForPoly(FLUID_DRAG*FLUID_DENSITY*clippedArea, clippedCount, clipped, cpvneg(cog), 0.0f); cpBodySetAngularVelocity(body, cpBodyGetAngularVelocity(body)*cpfexp(-w_damping*dt/cpBodyGetMoment(body))); return cpTrue; }
static void pullControlPoint(cpShape *shape) { int i; float origArea, newArea, newMass; control_point_t *cp; cpPolyShape *ps; cpCircleShape *circle; cpVect lp; cpVect verts[4]; cpConstraint *mouseJoint; mouseJoint = atlMouseJoint(); if (!mouseJoint) { lp = cpBodyWorld2Local(shape->body, atlMouseClickPos()); } else { /* update joint position */ lp = cpBodyWorld2Local(shape->body, atlMousePos()); atlRemoveMouseJoint(g_Space); } atlCreateMouseJoint(g_Space, shape->body, lp); cp = (control_point_t *)shape->data; ps = (cpPolyShape *)cp->dom->shape; control_point_t *circlePoint; for (i = 0; i < 4; ++i) { verts[i] = cpPolyShapeGetVert((cpShape *)ps, i); if (lp.x > 0) { if (verts[i].x > 0) verts[i].x = lp.x; else verts[i].x = -lp.x; } else if (lp.x < 0) { if (verts[i].x < 0) verts[i].x = lp.x; else verts[i].x = -lp.x; } if (lp.y > 0) { if (verts[i].y > 0) verts[i].y = lp.y; else verts[i].y = -lp.y; } else if (lp.y < 0) { if (verts[i].y < 0) verts[i].y = lp.y; else verts[i].y = -lp.y; } circlePoint = (control_point_t *)cp->dom->pControlPoints[i]; circle = (cpCircleShape *)circlePoint->shape; cpCircleShapeSetOffset((cpShape *)circle, verts[i]); } origArea = (fabs(dominoVerts[0].x)+dominoVerts[3].x) * (fabs(dominoVerts[0].y)+dominoVerts[1].y); newArea = (fabs(verts[0].x)+verts[3].x) * (fabs(verts[0].y)+verts[1].y); if (newArea > origArea) newMass = newArea/origArea * 0.05f; else newMass = 1.0f; cpBodySetMass(cp->dom->body, newMass); cpPolyShapeSetVerts((cpShape *)ps, ps->numVerts, verts, cpvzero); }