diff --git a/examples/Box2DExample/Box2DExample.upp b/examples/Box2DExample/Box2DExample.upp new file mode 100644 index 000000000..e6ffabf6a --- /dev/null +++ b/examples/Box2DExample/Box2DExample.upp @@ -0,0 +1,12 @@ +description "Box2D \"Bridge\" example \377"; + +uses + CtrlLib, + plugin\box2d; + +file + main.cpp; + +mainconfig + "" = "GUI"; + diff --git a/examples/Box2DExample/init b/examples/Box2DExample/init new file mode 100644 index 000000000..4c195a0cd --- /dev/null +++ b/examples/Box2DExample/init @@ -0,0 +1,5 @@ +#ifndef _Box2DExample_icpp_init_stub +#define _Box2DExample_icpp_init_stub +#include "CtrlLib/init" +#include "plugin\box2d/init" +#endif diff --git a/examples/Box2DExample/main.cpp b/examples/Box2DExample/main.cpp new file mode 100644 index 000000000..e47d70bd8 --- /dev/null +++ b/examples/Box2DExample/main.cpp @@ -0,0 +1,352 @@ +#include +#include + +using namespace Upp; + +struct QueryCallback : b2QueryCallback +{ + QueryCallback(const b2Vec2& point) + { + m_point = point; + m_fixture = NULL; + } + + bool ReportFixture(b2Fixture* fixture) + { + b2Body* body = fixture->GetBody(); + if (body->GetType() == b2_dynamicBody) + { + bool inside = fixture->TestPoint(m_point); + if (inside) + { + m_fixture = fixture; + return false; + } + } + + return true; + } + + b2Vec2 m_point; + b2Fixture* m_fixture; +}; + +struct DebugDraw : b2DebugDraw +{ + Draw* w; + Sizef sz; + float cx, cy; + float aspect; + + void DrawPolygon(const b2Vec2* v, int vertexCount, const b2Color& color) + { + Vector p; + p.SetCount(vertexCount + 1); + for(int i = 0; i < vertexCount; ++i) + { + p[i].x = int(v[i].x * aspect + cx); + p[i].y = int(cy - v[i].y * aspect); + } + p[vertexCount - 1].x = int(v[0].x); + p[vertexCount - 1].y = int(v[0].x); + + Color bg(int(color.r * 255.0), int(color.g * 255.0), int(color.b * 255.0)); + Color fg(int(color.r * 150.0), int(color.g * 150.0), int(color.b * 150.0)); + + w->DrawPolyline(p, vertexCount, 1, fg); + } + + void DrawSolidPolygon(const b2Vec2* v, int vertexCount, const b2Color& color) + { + Vector p; + p.SetCount(vertexCount); + for(int i = 0; i < vertexCount; ++i) + { + p[i].x = int(v[i].x * aspect + cx); + p[i].y = int(cy - v[i].y * aspect); + } + + Color bg(int(color.r * 255.0), int(color.g * 255.0), int(color.b * 255.0)); + Color fg(int(color.r * 150.0), int(color.g * 150.0), int(color.b * 150.0)); + + w->DrawPolygon(p, bg, 1, fg); + } + + void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color) + { + float r = aspect * radius * 2.0f; + int x = int((center.x - radius) * aspect + cx); + int y = int(cy - (center.y + radius) * aspect); + Color fg(int(color.r * 150.0), int(color.g * 150.0), int(color.b * 150.0)); + w->DrawEllipse(x, y, int(r), int(r), fg); + } + + void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color) + { + float r = aspect * radius * 2.0f; + int x = int((center.x - radius) * aspect + cx); + int y = int(cy - (center.y + radius) * aspect); + Color bg(int(color.r * 255.0), int(color.g * 255.0), int(color.b * 255.0)); + Color fg(int(color.r * 150.0), int(color.g * 150.0), int(color.b * 150.0)); + w->DrawEllipse(x, y, int(r), int(r), bg, 1, fg); + } + + void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color) + { + Color fg(int(color.r * 150.0), int(color.g * 150.0), int(color.b * 150.0)); + int x0 = int(p1.x * aspect + cx); + int y0 = int(cy - p1.y * aspect); + int x1 = int(p2.x * aspect + cx); + int y1 = int(cy - p2.y * aspect); + w->DrawLine(x0, y0, x1, y1, 1, fg); + } + + void DrawTransform(const b2Transform& xf) + { + } + + void DrawPoint(const b2Vec2& p, float32 size, const b2Color& color) + { + } + + void DrawString(int x, int y, const char* string, ...) + { + } + + void DrawAABB(b2AABB* aabb, const b2Color& color) + { + } +}; + +struct App : TopWindow +{ + b2Body* m_middle; + b2World* m_world; + b2MouseJoint* m_mouseJoint; + DebugDraw m_debugDraw; + b2Vec2 m_mouseWorld; + b2Body* m_groundBody; + b2AABB m_worldAABB; + + typedef App CLASSNAME; + + App() + { + Sizeable().Zoomable(); + Bridge(); + SetTimeCallback(-10, THISBACK(Render0)); + BackPaint(); + m_mouseJoint = NULL; + } + ~App() + { + delete m_world; + } + + void Bridge() + { + const int e_count = 30; + b2Vec2 gravity; + gravity.Set(0.0f, -10.0f); + + bool doSleep = true; + + m_world = new b2World(gravity, doSleep); + m_world->SetDebugDraw(&m_debugDraw); + + + b2BodyDef bd; + b2Body* ground = m_world->CreateBody(&bd); + + b2PolygonShape shape; + shape.SetAsEdge(b2Vec2(-40.0f, 0.0f), b2Vec2(40.0f, 0.0f)); + ground->CreateFixture(&shape, 0.0f); + + shape.SetAsBox(0.5f, 0.125f); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 20.0f; + fd.friction = 0.2f; + + b2RevoluteJointDef jd; + + b2Body* prevBody = ground; + for(int i = 0; i < e_count; ++i) + { + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-14.5f + 1.0f * i, 5.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + + b2Vec2 anchor(-15.0f + 1.0f * i, 5.0f); + jd.Initialize(prevBody, body, anchor); + m_world->CreateJoint(&jd); + + if (i == (e_count >> 1)) + { + m_middle = body; + } + prevBody = body; + } + + b2Vec2 anchor(-15.0f + 1.0f * e_count, 5.0f); + jd.Initialize(prevBody, ground, anchor); + m_world->CreateJoint(&jd); + + for(int i = 0; i < 2; ++i) + { + b2Vec2 vertices[3]; + vertices[0].Set(-0.5f, 0.0f); + vertices[1].Set(0.5f, 0.0f); + vertices[2].Set(0.0f, 1.5f); + + b2PolygonShape shape; + shape.Set(vertices, 3); + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-8.0f + 8.0f * i, 12.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + } + + for(int i = 0; i < 3; ++i) + { + b2CircleShape shape; + shape.m_radius = 0.5f; + + b2FixtureDef fd; + fd.shape = &shape; + fd.density = 1.0f; + + b2BodyDef bd; + bd.type = b2_dynamicBody; + bd.position.Set(-6.0f + 6.0f * i, 10.0f); + b2Body* body = m_world->CreateBody(&bd); + body->CreateFixture(&fd); + } + } + + void Step(float hz = 60, int velocityIterations = 8, int positionIterations = 3) + { + float32 timeStep = 1.0f / hz; + + int flags = 0; + flags += b2DebugDraw::e_shapeBit; + m_debugDraw.SetFlags(flags); + + m_world->SetWarmStarting(1); + m_world->SetContinuousPhysics(1); + m_world->Step(timeStep, velocityIterations, positionIterations); + m_world->DrawDebugData(); + } + + b2Vec2 ConvertScreenToWorld(int x, int y) + { + Size sz = GetSize(); + x += sz.cx / 2; + y = sz.cy / 2 - y; + float32 u = x / float32(sz.cx); + float32 v = (sz.cy - y) / float32(sz.cy); + + float32 ratio = float32(sz.cx) / float32(sz.cy); + b2Vec2 extents(ratio * 25.0f, 25.0f); + + b2Vec2 viewCenter(0.0f, 0.0f); + b2Vec2 lower = viewCenter - extents; + b2Vec2 upper = viewCenter + extents; + + b2Vec2 p; + p.x = (1.0f - u) * lower.x + u * upper.x; + p.y = (1.0f - v) * lower.y + v * upper.y; + return p; + } + + void Render0() + { + Refresh(); + } + + void Render(Draw& w) + { + Size sz = GetSize(); + m_debugDraw.w = &w; + m_debugDraw.sz = sz; + m_debugDraw.cx = sz.cx / 2.0f; + m_debugDraw.cy = sz.cy / 2.0f; + m_debugDraw.aspect = 18.0f; + + Step(); + } + + virtual void Paint(Draw& w) + { + Size sz = GetSize(); + w.DrawRect(sz, White); + Render(w); + } + + virtual void LeftDown(Point p0, dword keyflags) + { + b2Vec2 p(float32(p0.x), float32(p0.y)); + m_mouseWorld = ConvertScreenToWorld(p0.x, p0.y); + + if(m_mouseJoint != NULL) + return; + + b2AABB aabb; + b2Vec2 d; + d.Set(0.001f, 0.001f); + aabb.lowerBound = p - d; + aabb.upperBound = p + d; + + QueryCallback callback(p); + m_world->QueryAABB(&callback, aabb); + + if (callback.m_fixture) + { + b2Body* body = callback.m_fixture->GetBody(); + b2MouseJointDef md; + md.bodyA = m_groundBody; + md.bodyB = body; + md.target = p; + md.maxForce = 1000.0f * body->GetMass(); + m_mouseJoint = (b2MouseJoint*)m_world->CreateJoint(&md); + body->SetAwake(true); + } + } + + virtual void LeftUp(Point p0, dword keyflags) + { + b2Vec2 p = ConvertScreenToWorld(p0.x, p0.y); + if (m_mouseJoint) + { + m_world->DestroyJoint(m_mouseJoint); + m_mouseJoint = NULL; + } + } + + virtual void MouseMove(Point p0, dword keyflags) + { + b2Vec2 p = ConvertScreenToWorld(p0.x, p0.y); + + m_mouseWorld = p; + + if (m_mouseJoint) + { + m_mouseJoint->SetTarget(p); + } + } +}; + +GUI_APP_MAIN +{ + App().Run(); +} +