Beispiel #1
0
	b2SolveTask(int32 bodyCount, int32 contactCount, int32 jointCount,
		b2Body** bodies, b2Contact** contacts, b2Joint** joints,
		b2Velocity* velocities, b2Position* positions, b2ContactListener* listener,
		const b2TimeStep& timestep, b2Vec2 gravity, bool allowSleep,
		b2SolveTask* next)
		: m_island(bodyCount, contactCount, jointCount,
		bodies, contacts, joints,
		velocities, positions, listener)
	{
		m_timestep = &timestep;
		m_gravity = gravity;
		m_allowSleep = allowSleep;
		m_next = next;
		SetCost(b2GetIslandCost(bodyCount, contactCount, jointCount));
	}
Beispiel #2
0
    void AddIsland(int32 bodyCount, int32 contactCount, int32 jointCount,
        b2Body** bodies, b2Contact** contacts, b2Joint** joints,
        b2Velocity* velocities, b2Position* positions)
    {
        m_islands[m_islandCount++] = b2Island(
            bodyCount, contactCount, jointCount,
            bodies, contacts, joints,
            velocities, positions, m_contactListener);

        m_bodyCount += bodyCount;
        m_contactCount += contactCount;
        m_jointCount += jointCount;

        SetCost(b2GetIslandCost(m_bodyCount, m_contactCount, m_jointCount));
    }
Beispiel #3
0
void b2World::SolveMT(const b2TimeStep& step)
{
	b2SolveTask* solveTaskList = NULL;
	b2TaskGroup solveGroup(*m_threadPool);

	int32 allBodiesCapacity = m_bodyCount + m_contactManager.GetContactCount() + m_jointCount;
	int32 allContactsCapacity = m_contactManager.GetContactCount();
	int32 allJointsCapacity = m_jointCount;

	b2Body** allBodies = (b2Body**)m_stackAllocator.Allocate(allBodiesCapacity * sizeof(b2Body*));
	b2Contact** allContacts = (b2Contact**)m_stackAllocator.Allocate(allContactsCapacity * sizeof(b2Contact*));
	b2Joint** allJoints = (b2Joint**)m_stackAllocator.Allocate(allJointsCapacity * sizeof(b2Joint*));
	b2Velocity* allVelocities = (b2Velocity*)m_stackAllocator.Allocate(allBodiesCapacity * sizeof(b2Velocity));
	b2Position* allPositions = (b2Position*)m_stackAllocator.Allocate(allBodiesCapacity * sizeof(b2Position));
	int32 allBodiesCount = 0;
	int32 allContactsCount = 0;
	int32 allJointsCount = 0;

	b2Body** bodies = allBodies;
	b2Contact** contacts = allContacts;
	b2Joint** joints = allJoints;
	b2Velocity* velocities = allVelocities;
	b2Position* positions = allPositions;
	int32 bodyCount = 0;
	int32 contactCount = 0;
	int32 jointCount = 0;

	// Clear all the island flags.
	ClearIslandFlagsMT();

	b2Timer traversalTimer;

	// Build and simulate all awake islands.
	int32 stackSize = m_bodyCount;
	b2Body** stack = (b2Body**)m_stackAllocator.Allocate(stackSize * sizeof(b2Body*));
	for (int32 i = 0; i < m_nonStaticBodies.GetCount(); ++i)
	{
		b2Body* seed = m_nonStaticBodies.At(i);

		b2Assert(seed->GetType() != b2_staticBody);

		if (seed->m_flags & b2Body::e_islandFlag)
		{
			continue;
		}

		if (seed->IsAwake() == false || seed->IsActive() == false)
		{
			continue;
		}

		// Reset stack.		
		int32 stackCount = 0;
		stack[stackCount++] = seed;
		seed->m_flags |= b2Body::e_islandFlag;

		// Perform a depth first search (DFS) on the constraint graph.
		while (stackCount > 0)
		{
			// Grab the next body off the stack and add it to the island.
			b2Body* b = stack[--stackCount];
			b2Assert(b->IsActive() == true);
			bodies[bodyCount++] = b;

			// Make sure the body is awake.
			b->SetAwake(true);

			// To keep islands as small as possible, we don't
			// propagate islands across static bodies.
			if (b->GetType() == b2_staticBody)
			{
				continue;
			}

			// Search all contacts connected to this body.
			for (b2ContactEdge* ce = b->m_contactList; ce; ce = ce->next)
			{
				b2Contact* contact = ce->contact;

				// Has this contact already been added to an island?
				if (contact->m_flags & b2Contact::e_islandFlag)
				{
					continue;
				}

				// Is this contact solid and touching?
				if (contact->IsEnabled() == false ||
					contact->IsTouching() == false)
				{
					continue;
				}

				// Skip sensors.
				bool sensorA = contact->m_fixtureA->m_isSensor;
				bool sensorB = contact->m_fixtureB->m_isSensor;
				if (sensorA || sensorB)
				{
					continue;
				}

				contacts[contactCount++] = contact;
				contact->m_flags |= b2Contact::e_islandFlag;

				b2Body* other = ce->other;

				// Was the other body already added to this island?
				if (other->m_flags & b2Body::e_islandFlag)
				{
					continue;
				}

				b2Assert(stackCount < stackSize);
				stack[stackCount++] = other;
				other->m_flags |= b2Body::e_islandFlag;
			}

			// Search all joints connect to this body.
			for (b2JointEdge* je = b->m_jointList; je; je = je->next)
			{
				if (je->joint->m_islandFlag == true)
				{
					continue;
				}

				b2Body* other = je->other;

				// Don't simulate joints connected to inactive bodies.
				if (other->IsActive() == false)
				{
					continue;
				}

				joints[jointCount++] = je->joint;
				je->joint->m_islandFlag = true;

				if (other->m_flags & b2Body::e_islandFlag)
				{
					continue;
				}

				b2Assert(stackCount < stackSize);
				stack[stackCount++] = other;
				other->m_flags |= b2Body::e_islandFlag;
			}
		}

		// Post island traversal cleanup.
		for (int32 j = 0; j < bodyCount; ++j)
		{
			// Allow static bodies to participate in other islands.
			b2Body* b = bodies[j];
			if (b->GetType() == b2_staticBody)
			{
				b->m_flags &= ~b2Body::e_islandFlag;
			}
		}

		if (b2GetIslandCost(bodyCount, contactCount, jointCount) >= b2_minIslandCost)
		{
			b2SolveTask* task = (b2SolveTask*)m_blockAllocator.Allocate(sizeof(b2SolveTask));
			new(task)b2SolveTask(bodyCount, contactCount, jointCount,
				bodies, contacts, joints, velocities, positions,
				m_contactManager.m_contactListener,
				step, m_gravity, m_allowSleep, solveTaskList);
			solveTaskList = task;

			bodies += bodyCount;
			contacts += contactCount;
			joints += jointCount;
			velocities += bodyCount;
			positions += bodyCount;

			allBodiesCount += bodyCount;
			allContactsCount += contactCount;
			allJointsCount += jointCount;

			bodyCount = 0;
			contactCount = 0;
			jointCount = 0;

			b2Assert(allBodiesCount <= allBodiesCapacity);
			b2Assert(allContactsCount <= allContactsCapacity);
			b2Assert(allJointsCount <= allJointsCapacity);

			solveGroup.SubmitTask(task);
		}
	}

	// Pick up stragglers.
	if (bodyCount > 0)
	{
		b2SolveTask* task = (b2SolveTask*)m_blockAllocator.Allocate(sizeof(b2SolveTask));
		new(task)b2SolveTask(bodyCount, contactCount, jointCount,
			bodies, contacts, joints, velocities, positions,
			m_contactManager.m_contactListener,
			step, m_gravity, m_allowSleep, solveTaskList);
		solveTaskList = task;

		allBodiesCount += bodyCount;
		allContactsCount += contactCount;
		allJointsCount += jointCount;

		b2Assert(allBodiesCount <= allBodiesCapacity);
		b2Assert(allContactsCount <= allContactsCapacity);
		b2Assert(allJointsCount <= allJointsCapacity);

		solveGroup.SubmitTask(task);
	}

	m_profile.solveTraversal += traversalTimer.GetMilliseconds();

	// Wait for tasks to finish.
	solveGroup.Wait(m_stackAllocator);

	// Deallocate tasks.
	while (solveTaskList)
	{
		b2SolveTask* task = solveTaskList;

		// Save profile times.
		m_profile.solveInit += task->GetProfile().solveInit;
		m_profile.solveVelocity += task->GetProfile().solveVelocity;
		m_profile.solvePosition += task->GetProfile().solvePosition;

		solveTaskList = solveTaskList->GetNext();

		// Free the task
		task->~b2SolveTask();
		m_blockAllocator.Free(task, sizeof(b2SolveTask));
	}

	// Free stack
	m_stackAllocator.Free(stack);

	// Free island memory.
	m_stackAllocator.Free(allPositions);
	m_stackAllocator.Free(allVelocities);
	m_stackAllocator.Free(allJoints);
	m_stackAllocator.Free(allContacts);
	m_stackAllocator.Free(allBodies);

	{
		b2Timer timer;

		// Synchronize fixtures, check for out of range bodies.
		SynchronizeFixturesMT();

		m_profile.broadphaseSyncFixtures += timer.GetMilliseconds();

		{
			b2Timer timer2;

			// Look for new contacts.
			FindNewContactsMT();

			m_profile.broadphaseFindContacts += timer2.GetMilliseconds();
		}

		float32 broadPhaseTime = timer.GetMilliseconds();
		m_profile.broadphase += broadPhaseTime;
		m_profile.solve -= broadPhaseTime;
	}
}