| /* | |
| * Copyright (c) 2009 Erin Catto http://www.box2d.org | |
| * | |
| * This software is provided 'as-is', without any express or implied | |
| * warranty. In no event will the authors be held liable for any damages | |
| * arising from the use of this software. | |
| * Permission is granted to anyone to use this software for any purpose, | |
| * including commercial applications, and to alter it and redistribute it | |
| * freely, subject to the following restrictions: | |
| * 1. The origin of this software must not be misrepresented; you must not | |
| * claim that you wrote the original software. If you use this software | |
| * in a product, an acknowledgment in the product documentation would be | |
| * appreciated but is not required. | |
| * 2. Altered source versions must be plainly marked as such, and must not be | |
| * misrepresented as being the original software. | |
| * 3. This notice may not be removed or altered from any source distribution. | |
| */ | |
| #ifndef DYNAMIC_TREE_TEST_H | |
| #define DYNAMIC_TREE_TEST_H | |
| class DynamicTreeTest : public Test | |
| { | |
| public: | |
| enum | |
| { | |
| e_actorCount = 128 | |
| }; | |
| DynamicTreeTest() | |
| { | |
| m_worldExtent = 15.0f; | |
| m_proxyExtent = 0.5f; | |
| srand(888); | |
| for (int32 i = 0; i < e_actorCount; ++i) | |
| { | |
| Actor* actor = m_actors + i; | |
| GetRandomAABB(&actor->aabb); | |
| actor->proxyId = m_tree.CreateProxy(actor->aabb, actor); | |
| } | |
| m_stepCount = 0; | |
| float32 h = m_worldExtent; | |
| m_queryAABB.lowerBound.Set(-3.0f, -4.0f + h); | |
| m_queryAABB.upperBound.Set(5.0f, 6.0f + h); | |
| m_rayCastInput.p1.Set(-5.0, 5.0f + h); | |
| m_rayCastInput.p2.Set(7.0f, -4.0f + h); | |
| //m_rayCastInput.p1.Set(0.0f, 2.0f + h); | |
| //m_rayCastInput.p2.Set(0.0f, -2.0f + h); | |
| m_rayCastInput.maxFraction = 1.0f; | |
| m_automated = false; | |
| } | |
| static Test* Create() | |
| { | |
| return new DynamicTreeTest; | |
| } | |
| void Step(Settings* settings) | |
| { | |
| B2_NOT_USED(settings); | |
| m_rayActor = NULL; | |
| for (int32 i = 0; i < e_actorCount; ++i) | |
| { | |
| m_actors[i].fraction = 1.0f; | |
| m_actors[i].overlap = false; | |
| } | |
| if (m_automated == true) | |
| { | |
| int32 actionCount = b2Max(1, e_actorCount >> 2); | |
| for (int32 i = 0; i < actionCount; ++i) | |
| { | |
| Action(); | |
| } | |
| } | |
| Query(); | |
| RayCast(); | |
| for (int32 i = 0; i < e_actorCount; ++i) | |
| { | |
| Actor* actor = m_actors + i; | |
| if (actor->proxyId == b2_nullNode) | |
| continue; | |
| b2Color c(0.9f, 0.9f, 0.9f); | |
| if (actor == m_rayActor && actor->overlap) | |
| { | |
| c.Set(0.9f, 0.6f, 0.6f); | |
| } | |
| else if (actor == m_rayActor) | |
| { | |
| c.Set(0.6f, 0.9f, 0.6f); | |
| } | |
| else if (actor->overlap) | |
| { | |
| c.Set(0.6f, 0.6f, 0.9f); | |
| } | |
| m_debugDraw.DrawAABB(&actor->aabb, c); | |
| } | |
| b2Color c(0.7f, 0.7f, 0.7f); | |
| m_debugDraw.DrawAABB(&m_queryAABB, c); | |
| m_debugDraw.DrawSegment(m_rayCastInput.p1, m_rayCastInput.p2, c); | |
| b2Color c1(0.2f, 0.9f, 0.2f); | |
| b2Color c2(0.9f, 0.2f, 0.2f); | |
| m_debugDraw.DrawPoint(m_rayCastInput.p1, 6.0f, c1); | |
| m_debugDraw.DrawPoint(m_rayCastInput.p2, 6.0f, c2); | |
| if (m_rayActor) | |
| { | |
| b2Color cr(0.2f, 0.2f, 0.9f); | |
| b2Vec2 p = m_rayCastInput.p1 + m_rayActor->fraction * (m_rayCastInput.p2 - m_rayCastInput.p1); | |
| m_debugDraw.DrawPoint(p, 6.0f, cr); | |
| } | |
| { | |
| int32 height = m_tree.GetHeight(); | |
| m_debugDraw.DrawString(5, m_textLine, "dynamic tree height = %d", height); | |
| m_textLine += 15; | |
| } | |
| ++m_stepCount; | |
| } | |
| void Keyboard(unsigned char key) | |
| { | |
| switch (key) | |
| { | |
| case 'a': | |
| m_automated = !m_automated; | |
| break; | |
| case 'c': | |
| CreateProxy(); | |
| break; | |
| case 'd': | |
| DestroyProxy(); | |
| break; | |
| case 'm': | |
| MoveProxy(); | |
| break; | |
| } | |
| } | |
| bool QueryCallback(int32 proxyId) | |
| { | |
| Actor* actor = (Actor*)m_tree.GetUserData(proxyId); | |
| actor->overlap = b2TestOverlap(m_queryAABB, actor->aabb); | |
| return true; | |
| } | |
| float32 RayCastCallback(const b2RayCastInput& input, int32 proxyId) | |
| { | |
| Actor* actor = (Actor*)m_tree.GetUserData(proxyId); | |
| b2RayCastOutput output; | |
| bool hit = actor->aabb.RayCast(&output, input); | |
| if (hit) | |
| { | |
| m_rayCastOutput = output; | |
| m_rayActor = actor; | |
| m_rayActor->fraction = output.fraction; | |
| return output.fraction; | |
| } | |
| return input.maxFraction; | |
| } | |
| private: | |
| struct Actor | |
| { | |
| b2AABB aabb; | |
| float32 fraction; | |
| bool overlap; | |
| int32 proxyId; | |
| }; | |
| void GetRandomAABB(b2AABB* aabb) | |
| { | |
| b2Vec2 w; w.Set(2.0f * m_proxyExtent, 2.0f * m_proxyExtent); | |
| //aabb->lowerBound.x = -m_proxyExtent; | |
| //aabb->lowerBound.y = -m_proxyExtent + m_worldExtent; | |
| aabb->lowerBound.x = RandomFloat(-m_worldExtent, m_worldExtent); | |
| aabb->lowerBound.y = RandomFloat(0.0f, 2.0f * m_worldExtent); | |
| aabb->upperBound = aabb->lowerBound + w; | |
| } | |
| void MoveAABB(b2AABB* aabb) | |
| { | |
| b2Vec2 d; | |
| d.x = RandomFloat(-0.5f, 0.5f); | |
| d.y = RandomFloat(-0.5f, 0.5f); | |
| //d.x = 2.0f; | |
| //d.y = 0.0f; | |
| aabb->lowerBound += d; | |
| aabb->upperBound += d; | |
| b2Vec2 c0 = 0.5f * (aabb->lowerBound + aabb->upperBound); | |
| b2Vec2 min; min.Set(-m_worldExtent, 0.0f); | |
| b2Vec2 max; max.Set(m_worldExtent, 2.0f * m_worldExtent); | |
| b2Vec2 c = b2Clamp(c0, min, max); | |
| aabb->lowerBound += c - c0; | |
| aabb->upperBound += c - c0; | |
| } | |
| void CreateProxy() | |
| { | |
| for (int32 i = 0; i < e_actorCount; ++i) | |
| { | |
| int32 j = rand() % e_actorCount; | |
| Actor* actor = m_actors + j; | |
| if (actor->proxyId == b2_nullNode) | |
| { | |
| GetRandomAABB(&actor->aabb); | |
| actor->proxyId = m_tree.CreateProxy(actor->aabb, actor); | |
| return; | |
| } | |
| } | |
| } | |
| void DestroyProxy() | |
| { | |
| for (int32 i = 0; i < e_actorCount; ++i) | |
| { | |
| int32 j = rand() % e_actorCount; | |
| Actor* actor = m_actors + j; | |
| if (actor->proxyId != b2_nullNode) | |
| { | |
| m_tree.DestroyProxy(actor->proxyId); | |
| actor->proxyId = b2_nullNode; | |
| return; | |
| } | |
| } | |
| } | |
| void MoveProxy() | |
| { | |
| for (int32 i = 0; i < e_actorCount; ++i) | |
| { | |
| int32 j = rand() % e_actorCount; | |
| Actor* actor = m_actors + j; | |
| if (actor->proxyId == b2_nullNode) | |
| { | |
| continue; | |
| } | |
| b2AABB aabb0 = actor->aabb; | |
| MoveAABB(&actor->aabb); | |
| b2Vec2 displacement = actor->aabb.GetCenter() - aabb0.GetCenter(); | |
| m_tree.MoveProxy(actor->proxyId, actor->aabb, displacement); | |
| return; | |
| } | |
| } | |
| void Action() | |
| { | |
| int32 choice = rand() % 20; | |
| switch (choice) | |
| { | |
| case 0: | |
| CreateProxy(); | |
| break; | |
| case 1: | |
| DestroyProxy(); | |
| break; | |
| default: | |
| MoveProxy(); | |
| } | |
| } | |
| void Query() | |
| { | |
| m_tree.Query(this, m_queryAABB); | |
| for (int32 i = 0; i < e_actorCount; ++i) | |
| { | |
| if (m_actors[i].proxyId == b2_nullNode) | |
| { | |
| continue; | |
| } | |
| bool overlap = b2TestOverlap(m_queryAABB, m_actors[i].aabb); | |
| B2_NOT_USED(overlap); | |
| b2Assert(overlap == m_actors[i].overlap); | |
| } | |
| } | |
| void RayCast() | |
| { | |
| m_rayActor = NULL; | |
| b2RayCastInput input = m_rayCastInput; | |
| // Ray cast against the dynamic tree. | |
| m_tree.RayCast(this, input); | |
| // Brute force ray cast. | |
| Actor* bruteActor = NULL; | |
| b2RayCastOutput bruteOutput; | |
| for (int32 i = 0; i < e_actorCount; ++i) | |
| { | |
| if (m_actors[i].proxyId == b2_nullNode) | |
| { | |
| continue; | |
| } | |
| b2RayCastOutput output; | |
| bool hit = m_actors[i].aabb.RayCast(&output, input); | |
| if (hit) | |
| { | |
| bruteActor = m_actors + i; | |
| bruteOutput = output; | |
| input.maxFraction = output.fraction; | |
| } | |
| } | |
| if (bruteActor != NULL) | |
| { | |
| b2Assert(bruteOutput.fraction == m_rayCastOutput.fraction); | |
| } | |
| } | |
| float32 m_worldExtent; | |
| float32 m_proxyExtent; | |
| b2DynamicTree m_tree; | |
| b2AABB m_queryAABB; | |
| b2RayCastInput m_rayCastInput; | |
| b2RayCastOutput m_rayCastOutput; | |
| Actor* m_rayActor; | |
| Actor m_actors[e_actorCount]; | |
| int32 m_stepCount; | |
| bool m_automated; | |
| }; | |
| #endif |