paulxstretch/deps/juce/examples/Assets/Box2DTests/DynamicTreeTest.h
essej 25bd5d8adb git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo:
  subdir:   "deps/juce"
  merged:   "b13f9084e"
upstream:
  origin:   "https://github.com/essej/JUCE.git"
  branch:   "sono6good"
  commit:   "b13f9084e"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo.git"
  commit:   "2f68596"
2022-04-18 17:51:22 -04:00

358 lines
9.3 KiB
C++

/*
* 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