{"size": 13163, "ext": "js", "max_stars_repo_path": "src/cpSpaceComponent.js", "max_stars_repo_name": "lytc/chipmunk-js", "max_stars_repo_stars_event_min_datetime": "2015-05-01T18:15:42.000Z", "max_stars_repo_stars_event_max_datetime": "2021-11-17T08:23:32.000Z", "max_issues_repo_path": "src/cpSpaceComponent.js", "max_issues_repo_name": "lytc/chipmunk-js", "max_issues_repo_issues_event_min_datetime": null, "max_issues_repo_issues_event_max_datetime": null, "max_forks_repo_path": "src/cpSpaceComponent.js", "max_forks_repo_name": "lytc/chipmunk-js", "max_forks_repo_forks_event_min_datetime": "2021-11-17T08:23:39.000Z", "max_forks_repo_forks_event_max_datetime": "2021-11-17T08:23:39.000Z"}
{"max_stars_count": 7, "max_issues_count": null, "max_forks_count": 1, "avg_line_length": 35.0079787234, "max_line_length": 151, "alphanum_fraction": 0.5948491985}
//MARK: Sleeping Functions

//void
Space.prototype.activateBody = function (/*cpBody*/ body) {
    var space = this;
    cpAssertHard(!body.isRogue(), "Internal error: Attempting to activate a rogue body.");

    if (space.locked) {
        // cpSpaceActivateBody() is called again once the space is unlocked
        if (-1 == space.rousedBodies.indexOf(body)) space.rousedBodies.push(body);
    } else {
        if (NDEBUG) {
            cpAssertSoft(body.nodeRoot == null && body.nodeNext == null, "Internal error: Activating body non-null node pointers.");
        }
        space.bodies.push(body);

        for (var shape = body.shapeList; shape; shape = shape.next) {
            space.staticShapes.remove(shape, shape.hashid);
            space.activeShapes.insert(shape, shape.hashid);
        }

        for (var arb = body.arbiterList; arb; arb = arb.next(body)) {
            /*cpBody*/
            var bodyA = arb.body_a;

            // Arbiters are shared between two bodies that are always woken up together.
            // You only want to restore the arbiter once, so bodyA is arbitrarily chosen to own the arbiter.
            // The edge case is when static bodies are involved as the static bodies never actually sleep.
            // If the static body is bodyB then all is good. If the static body is bodyA, that can easily be checked.
            if (body == bodyA || bodyA.isStatic()) {
//				/*int*/ var numContacts = arb.numContacts;
//				/*cpContact*/ var contacts = arb.contacts;

                // Restore contact values back to the space's contact buffer memory
//				arb.contacts = cpContactBufferGetArray(space);
//				memcpy(arb.contacts, contacts, numContacts*sizeof(cpContact));
//				space.pushContacts(numContacts);

                // Reinsert the arbiter into the arbiter cache
                /*cpShape*/
                var a = arb.a, b = arb.b;
//				cpShape *shape_pair[] = {a, b};
                /*cpHashValue*/
                var arbHashID = CP_HASH_PAIR(/*cpHashValue*/a.hashid, /*cpHashValue*/b.hashid);
//				cpHashSetInsert(space.cachedArbiters, arbHashID, shape_pair, arb, null);
                space.cachedArbiters[arbHashID] = arb;
                // Update the arbiter's state
                arb.stamp = space.stamp;
                arb.handler = space.lookupHandler(a.collision_type, b.collision_type);
                space.arbiters.push(arb);

//				cpfree(contacts);
            }
        }

        for (var constraint = body.constraintList; constraint; constraint = constraint.next(body)) {
            /*cpBody*/
            var bodyA = constraint.a;
            if (body == bodyA || bodyA.isStatic()) space.constraints.push(constraint);
        }
    }
}

//static void
Space.prototype.deactivateBody = function (/*cpBody*/ body) {
    var space = this;
    cpAssertHard(!body.isRogue(), "Internal error: Attempting to deactivate a rouge body.");
    cpArrayDeleteObj(space.bodies, body);

    for (var shape = body.shapeList; shape; shape = shape.next) {
        space.activeShapes.remove(shape, shape.hashid);
        space.staticShapes.insert(shape, shape.hashid);
    }

    for (var arb = body.arbiterList; arb; arb = arb.next(body)) {
        /*cpBody*/
        var bodyA = arb.body_a;
        if (body == bodyA || bodyA.isStatic()) {
            space.uncacheArbiter(arb);

            // Save contact values to a new block of memory so they won't time out
//			/*size_t*/ var bytes = arb.numContacts*sizeof(cpContact);
//			/*cpContact*/ var contacts = (cpContact *)cpcalloc(1, bytes);
//			memcpy(contacts, arb.contacts, bytes);
//			arb.contacts = contacts;
        }
    }

    for (var constraint = body.constraintList; constraint; constraint = constraint.next(body)) {
        /*cpBody*/
        var bodyA = constraint.a;
        if (body == bodyA || bodyA.isStatic()) cpArrayDeleteObj(space.constraints, constraint);
    }
}

//static inline cpBody *
var ComponentRoot = function (/*cpBody*/ body) {
    return (body ? body.nodeRoot : null);
}

//static inline void
var ComponentActivate = function (/*cpBody*/ root) {
    if (!root || !root.isSleeping()) return;
    cpAssertHard(!root.isRogue(), "Internal Error: ComponentActivate() called on a rogue body.");

    /*cpSpace*/
    var space = root.space;
    /*cpBody*/
    var body = root;
    while (body) {
        /*cpBody*/
        var next = body.nodeNext;

        body.nodeIdleTime = 0.0;
        body.nodeRoot = null;
        body.nodeNext = null;
        space.activateBody(body);

        body = next;
    }

    cpArrayDeleteObj(space.sleepingComponents, root);
}

//void
Body.prototype.activate = function () {
    var body = this;
    if (!body.isRogue()) {
        body.nodeIdleTime = 0.0;
        ComponentActivate(ComponentRoot(body));
    }

    for (var arb = body.arbiterList; arb; arb = arb.next(body)) {
        // Reset the idle timer of things the body is touching as well.
        // That way things don't get left hanging in the air.
        /*cpBody*/
        var other = (arb.body_a == body ? arb.body_b : arb.body_a);
        if (!other.isStatic()) other.nodeIdleTime = 0.0;
    }
}

//void
Body.prototype.activateStatic = function (/*cpShape*/ filter) {
    var body = this;
    cpAssertHard(body.isStatic(), "cpBodyActivateStatic() called on a non-static body.");

    for (var arb = body.arbiterList; arb; arb = arb.next(body)) {
        if (!filter || filter == arb.a || filter == arb.b) {
            (arb.body_a == body ? arb.body_b : arb.body_a).activate();
        }
    }

    // TODO should also activate joints?
}

//static inline void
Body.prototype.pushArbiter = function (/*cpArbiter*/ arb) {
    var body = this;
    if (NDEBUG) {
        cpAssertSoft(arb.threadForBody(body).next == null, "Internal Error: Dangling contact graph pointers detected. (A)");
        cpAssertSoft(arb.threadForBody(body).prev == null, "Internal Error: Dangling contact graph pointers detected. (B)");
    }

    /*cpArbiter*/
    var next = body.arbiterList;
    if (NDEBUG) {
        cpAssertSoft(next == null || next.threadForBody(body).prev == null, "Internal Error: Dangling contact graph pointers detected. (C)");
    }
    arb.threadForBody(body).next = next;

    if (next) next.threadForBody(body).prev = arb;
    body.arbiterList = arb;
}

//static inline void
var ComponentAdd = function (/*cpBody*/ root, /*cpBody*/ body) {
    body.nodeRoot = root;

    if (body != root) {
        body.nodeNext = root.nodeNext;
        root.nodeNext = body;
    }
}

//static inline void
var FloodFillComponent = function (/*cpBody*/ root, /*cpBody*/ body) {
    // Rogue bodies cannot be put to sleep and prevent bodies they are touching from sleepining anyway.
    // Static bodies (which are a type of rogue body) are effectively sleeping all the time.
    if (!body.isRogue()) {
        /*cpBody*/
        var other_root = ComponentRoot(body);
        if (other_root == null) {
            ComponentAdd(root, body);
            for (var arb = body.arbiterList; arb; arb = arb.next(body)) {
                FloodFillComponent(root, (body == arb.body_a ? arb.body_b : arb.body_a));
            }
            for (var constraint = body.constraintList; constraint; constraint = constraint.next(body)) {
                FloodFillComponent(root, (body == constraint.a ? constraint.b : constraint.a));
            }
        } else {
            if (NDEBUG) {
                cpAssertSoft(other_root == root, "Internal Error: Inconsistency dectected in the contact graph.");
            }
        }
    }
}

//static inline cpBool
var ComponentActive = function (/*cpBody*/ root, /*cpFloat*/ threshold) {
    for (var body = root; body; body = body.nodeNext) {
        if (body.nodeIdleTime < threshold) return true;
    }

    return false;
}

//void
Space.prototype.processComponents = function (/*cpFloat*/ dt) {
    var space = this;
    /*cpBool*/
    var sleep = (space.sleepTimeThreshold != Infinity);
    /*cpArray*/
    var bodies = space.bodies;

    if (NDEBUG) {
        for (var i = 0; i < bodies.length; i++) {
            /*cpBody*/
            var body = /*cpBody*/bodies[i];

            cpAssertSoft(body.nodeNext == null, "Internal Error: Dangling next pointer detected in contact graph.");
            cpAssertSoft(body.nodeRoot == null, "Internal Error: Dangling root pointer detected in contact graph.");
        }
    }

    // Calculate the kinetic energy of all the bodies.
    if (sleep) {
        /*cpFloat*/
        var dv = space.idleSpeedThreshold;
        /*cpFloat*/
        var dvsq = (dv ? dv * dv : cpvlengthsq(space.gravity) * dt * dt);

        // update idling and reset component nodes
        for (var i = 0; i < bodies.length; i++) {
            /*cpBody*/
            var body = /*cpBody*/bodies[i];

            // Need to deal with infinite mass objects
            /*cpFloat*/
            var keThreshold = (dvsq ? body.m * dvsq : 0.0);
            body.nodeIdleTime = (body.kineticEnergy() > keThreshold ? 0.0 : body.nodeIdleTime + dt);
        }
    }

    // Awaken any sleeping bodies found and then push arbiters to the bodies' lists.
    /*cpArray*/
    var arbiters = space.arbiters;
    for (var i = 0, count = arbiters.length; i < count; i++) {
        /*cpArbiter*/
        var arb = /*(cpArbiter*)*/arbiters[i];
        /*cpBody*/
        var a = arb.body_a, b = arb.body_b;

        if (sleep) {
            if ((b.isRogue() && !b.isStatic()) || a.isSleeping()) a.activate();
            if ((a.isRogue() && !a.isStatic()) || b.isSleeping()) b.activate();
        }

        a.pushArbiter(arb);
        b.pushArbiter(arb);
    }

    if (sleep) {
        // Bodies should be held active if connected by a joint to a non-static rouge body.
        /*cpArray*/
        var constraints = space.constraints;
        for (var i = 0; i < constraints.length; i++) {
            /*cpConstraint*/
            var constraint = /*cpConstraint*/constraints[i];
            /*cpBody*/
            var a = constraint.a, b = constraint.b;

            if (b.isRogue() && !b.isStatic()) a.activate();
            if (a.isRogue() && !a.isStatic()) b.activate();
        }

        // Generate components and deactivate sleeping ones
        for (var i = 0; i < bodies.length;) {
            /*cpBody*/
            var body = /*cpBody*/bodies[i];

            if (ComponentRoot(body) == null) {
                // Body not in a component yet. Perform a DFS to flood fill mark
                // the component in the contact graph using this body as the root.
                FloodFillComponent(body, body);

                // Check if the component should be put to sleep.
                if (!ComponentActive(body, space.sleepTimeThreshold)) {
                    space.sleepingComponents.push(body);
                    for (var other = body; other; other = other.nodeNext) {
                        space.deactivateBody(other);
                    }

                    // cpSpaceDeactivateBody() removed the current body from the list.
                    // Skip incrementing the index counter.
                    continue;
                }
            }

            i++;

            // Only sleeping bodies retain their component node pointers.
            body.nodeRoot = null;
            body.nodeNext = null;
        }
    }
}

//void
Body.prototype.sleep = function () {
    var body = this;
    body.sleepWithGroup(null);
}

//void
Body.prototype.sleepWithGroup = function (/*cpBody*/ group) {
    var body = this;
    cpAssertHard(!body.isRogue(), "Rogue (and static) bodies cannot be put to sleep.");

    /*cpSpace*/
    var space = body.space;
    cpAssertHard(!space.locked, "Bodies cannot be put to sleep during a query or a call to cpSpaceStep(). Put these calls into a post-step callback.");
    cpAssertHard(group == null || group.isSleeping(), "Cannot use a non-sleeping body as a group identifier.");

    if (body.isSleeping()) {
        cpAssertHard(ComponentRoot(body) == ComponentRoot(group), "The body is already sleeping and it's group cannot be reassigned.");
        return;
    }

    for (var shape = body.shapeList; shape; shape = shape.next) shape.update(body.p, body.rot);
    space.deactivateBody(body);

    if (group) {
        /*cpBody*/
        var root = ComponentRoot(group);

//		/*cpComponentNode*/ var node = new cpComponentNode(root, root.node.next, 0.0);
        body.nodeRoot = root;
        body.nodeNext = root.nodeNext;
        body.nodeIdleTime = 0.0;

        root.nodeNext = body;
    } else {
//		/*cpComponentNode*/ var node = new cpComponentNode(body, null, 0.0);
        body.nodeRoot = body;
        body.nodeNext = null;
        body.nodeIdleTime = 0.0;

        space.sleepingComponents.push(body);
    }

    cpArrayDeleteObj(space.bodies, body);
}

//static void
var activateTouchingHelper = function (/*cpShape*/ shape) {
    shape.body.activate();
}

//void
Space.prototype.activateShapesTouchingShape = function (/*cpShape*/ shape) {
    var space = this;
    if (space.sleepTimeThreshold != Infinity) {
        space.shapeQuery(shape, /*cpSpaceShapeQueryFunc*/activateTouchingHelper, shape);
    }
}
