Adding dali letters to 2d phys demo 73/298273/8
authorDavid Steele <david.steele@samsung.com>
Mon, 4 Sep 2023 17:42:49 +0000 (18:42 +0100)
committerDavid Steele <david.steele@samsung.com>
Fri, 8 Sep 2023 16:51:49 +0000 (16:51 +0000)
Added "hanging" letters that can pivot about some point
Now, the balls interact with the letters, and fire off
with a huge impulse periodically to bring some life to
the demo!

Change-Id: Ieecacc3b27e4e55174cb86d1075c9b1739ae0bc3

13 files changed:
examples/bullet-physics/physics-demo-controller.cpp
examples/chipmunk-physics/README.md
examples/chipmunk-physics/dletter.blend [new file with mode: 0755]
examples/chipmunk-physics/letter-a.h [new file with mode: 0755]
examples/chipmunk-physics/letter-d.h [new file with mode: 0755]
examples/chipmunk-physics/letter-i.h [new file with mode: 0755]
examples/chipmunk-physics/letter-l.h [new file with mode: 0755]
examples/chipmunk-physics/physics-demo-controller.cpp
examples/chipmunk-physics/split-letter-d.h [new file with mode: 0644]
resources/images/dali-logo-a.png [new file with mode: 0644]
resources/images/dali-logo-d.png [new file with mode: 0644]
resources/images/dali-logo-i.png [new file with mode: 0644]
resources/images/dali-logo-l.png [new file with mode: 0644]

index 93ec771..40fdc59 100644 (file)
@@ -303,8 +303,9 @@ public:
             Vector3 localPivot;
             Vector3 rayPhysicsOrigin;
             Vector3 rayPhysicsEnd;
+            Dali::Any nullFilter;
             mPhysicsAdaptor.BuildPickingRay(origin, direction, rayPhysicsOrigin, rayPhysicsEnd);
-            auto body = scopedAccessor->HitTest(rayPhysicsOrigin, rayPhysicsEnd, localPivot, mOldPickingDistance);
+            auto body = scopedAccessor->HitTest(rayPhysicsOrigin, rayPhysicsEnd, nullFilter, localPivot, mOldPickingDistance);
             if(!body.Empty())
             {
               mPickedBody = body.Get<btRigidBody*>();
index 287fa27..897d948 100644 (file)
@@ -1,7 +1,9 @@
 # Chipmunk Physics Example
 
 This is an example showing how to use Chipmunk2D physics library to create and control physics objects in DALi.
-It creates a set of balls which act under gravity
+It creates a set of balls which act under gravity, and the letters of the DALi logo that are each "suspended" from 
+a fixed pivot. Every 7 seconds, a random number of the balls are given a high impulse to bring the whole demo back
+to life.
 
 ![](./chipmunk.gif)
 
@@ -9,3 +11,4 @@ It creates a set of balls which act under gravity
 "qe" keys rotate the last touched actor in Z axis
 "p" key resets the position/forces on the last touched actor to the origin
 Space key toggles the integration state.
+"m" key toggles the debug state
diff --git a/examples/chipmunk-physics/dletter.blend b/examples/chipmunk-physics/dletter.blend
new file mode 100755 (executable)
index 0000000..1d5c23a
Binary files /dev/null and b/examples/chipmunk-physics/dletter.blend differ
diff --git a/examples/chipmunk-physics/letter-a.h b/examples/chipmunk-physics/letter-a.h
new file mode 100755 (executable)
index 0000000..cbac134
--- /dev/null
@@ -0,0 +1,62 @@
+double letter_a[] = {
+0.080334, -0.445639,
+-0.050940, -0.447993,
+-0.175007, -0.428650,
+-0.275208, -0.394296,
+-0.349133, -0.348910,
+-0.399168, -0.296059,
+-0.429146, -0.239705,
+-0.444190, -0.184144,
+-0.449309, -0.133031,
+-0.447807, -0.088260,
+-0.441110, -0.049854,
+-0.429090, -0.016322,
+-0.411267, 0.013977,
+-0.387297, 0.042290,
+-0.356968, 0.069448,
+-0.320038, 0.095734,
+-0.276016, 0.120705,
+-0.224141, 0.143171,
+-0.163786, 0.161366,
+-0.096207, 0.173662,
+-0.025351, 0.178901,
+0.042247, 0.176440,
+0.099742, 0.166799,
+0.143348, 0.152616,
+0.172828, 0.138790,
+0.191163, 0.131669,
+0.202876, 0.135037,
+0.213151, 0.148009,
+0.227734, 0.165069,
+0.251264, 0.178894,
+0.284487, 0.185042,
+0.323773, 0.182775,
+0.361894, 0.174502,
+0.392529, 0.162594,
+0.412959, 0.147477,
+0.424129, 0.127583,
+0.429248, 0.100184,
+0.431109, 0.063005,
+0.431556, 0.014540,
+0.431537, -0.045757,
+0.431509, -0.116220,
+0.431712, -0.192109,
+0.432178, -0.265634,
+0.432602, -0.328082,
+0.432049, -0.374457,
+0.428895, -0.404558,
+0.420987, -0.422551,
+0.406962, -0.433552,
+0.387266, -0.440988,
+0.364196, -0.446436,
+0.341061, -0.450080,
+0.320084, -0.451858,
+0.301841, -0.451758,
+0.285388, -0.449827,
+0.269461, -0.446152,
+0.253532, -0.440856,
+0.237876, -0.434095,
+0.222830, -0.426206,
+0.206674, -0.418119,
+0.184985, -0.411483,
+};
diff --git a/examples/chipmunk-physics/letter-d.h b/examples/chipmunk-physics/letter-d.h
new file mode 100755 (executable)
index 0000000..29f0208
--- /dev/null
@@ -0,0 +1,64 @@
+double letter_d[] = {
+0.131136, -0.445716,
+0.210390, -0.423237,
+0.262577, -0.399065,
+0.303066, -0.375918,
+0.337334, -0.354157,
+0.351012, -0.340831,
+0.375016, -0.322534,
+0.396490, -0.293488,
+0.416732, -0.270408,
+0.434497, -0.237234,
+0.452636, -0.199979,
+0.462341, -0.155056,
+0.466712, -0.072655,
+0.468917, 0.030611,
+0.469557, 0.141277,
+0.468970, 0.241971,
+0.466592, 0.321481,
+0.463973, 0.370117,
+0.449290, 0.412602,
+0.430514, 0.435231,
+0.405080, 0.449557,
+0.375657, 0.458505,
+0.345982, 0.463514,
+0.318714, 0.465354,
+0.294957, 0.464321,
+0.274400, 0.460291,
+0.256365, 0.453172,
+0.240564, 0.443229,
+0.227141, 0.431093,
+0.216465, 0.417345,
+0.208675, 0.401603,
+0.203567, 0.382294,
+0.200628, 0.356920,
+0.199298, 0.324164,
+0.199170, 0.285514,
+0.200000, 0.245338,
+0.201478, 0.209592,
+0.202679, 0.182716,
+0.201921, 0.166840,
+0.196805, 0.161833,
+0.184565, 0.165839,
+0.162353, 0.175720,
+0.127279, 0.187103,
+0.077452, 0.195250,
+0.014636, 0.197297,
+-0.055010, 0.192870,
+-0.121485, 0.183899,
+-0.176149, 0.172829,
+-0.216299, 0.161038,
+-0.245481, 0.148720,
+-0.271343, 0.135014,
+-0.299749, 0.118339,
+-0.333036, 0.096502,
+-0.370072, 0.066624,
+-0.407117, 0.024452,
+-0.438623, -0.036298,
+-0.457155, -0.123895,
+-0.443017, -0.239761,
+-0.333914, -0.370416,
+-0.238509, -0.415552,
+-0.143103, -0.447210,
+-0.015264, -0.458859,
+};
diff --git a/examples/chipmunk-physics/letter-i.h b/examples/chipmunk-physics/letter-i.h
new file mode 100755 (executable)
index 0000000..974e1ca
--- /dev/null
@@ -0,0 +1,62 @@
+double letter_i[] = {
+0.064721, 0.397047,
+0.084359, 0.392005,
+0.106181, 0.384591,
+0.125922, 0.375744,
+0.142219, 0.366343,
+0.154761, 0.356927,
+0.163984, 0.347651,
+0.170804, 0.338367,
+0.175946, 0.328809,
+0.179775, 0.318644,
+0.182339, 0.307542,
+0.177591, 0.258003,
+0.148165, 0.224480,
+0.111786, 0.209128,
+0.092304, 0.197781,
+0.091241, 0.194700,
+0.110808, 0.181851,
+0.144725, 0.163438,
+0.168692, 0.140330,
+0.174015, 0.027886,
+0.174833, -0.060661,
+0.175642, -0.162698,
+0.176388, -0.255385,
+0.176999, -0.322609,
+0.177447, -0.361523,
+0.176470, -0.404438,
+0.156498, -0.440912,
+0.128113, -0.461851,
+0.079571, -0.474461,
+0.032029, -0.476380,
+-0.006020, -0.470540,
+-0.051020, -0.453217,
+-0.078452, -0.436259,
+-0.088338, -0.425531,
+-0.099007, -0.405238,
+-0.104707, -0.324290,
+-0.104555, -0.251683,
+-0.104249, -0.160428,
+-0.103978, -0.069679,
+-0.103846, 0.002851,
+-0.103784, 0.050585,
+-0.103546, 0.078313,
+-0.101804, 0.106063,
+-0.086488, 0.143888,
+-0.047079, 0.166131,
+-0.007868, 0.197018,
+-0.056347, 0.222110,
+-0.084005, 0.244999,
+-0.094406, 0.286331,
+-0.090557, 0.322635,
+-0.086423, 0.332826,
+-0.081092, 0.342019,
+-0.074727, 0.350617,
+-0.067183, 0.359181,
+-0.057354, 0.368154,
+-0.043032, 0.377802,
+-0.021385, 0.387927,
+0.009406, 0.396920,
+0.051950, 0.399662,
+
+};
diff --git a/examples/chipmunk-physics/letter-l.h b/examples/chipmunk-physics/letter-l.h
new file mode 100755 (executable)
index 0000000..6abff43
--- /dev/null
@@ -0,0 +1,37 @@
+double letter_l[] = {
+-0.105263, -0.207440,
+-0.108182, 0.173937,
+-0.109280, 0.299948,
+-0.109283, 0.340490,
+-0.105907, 0.372182,
+-0.104059, 0.380107,
+-0.091231, 0.409253,
+-0.069112, 0.431754,
+-0.039130, 0.446449,
+-0.005093, 0.454614,
+0.029018, 0.457917,
+0.060424, 0.457140,
+0.087614, 0.452122,
+0.110104, 0.442246,
+0.127851, 0.427662,
+0.141076, 0.409636,
+0.150263, 0.390488,
+0.156066, 0.372701,
+0.159670, 0.354752,
+0.160219, 0.303937,
+0.160569, 0.152952,
+0.160810, 0.034914,
+0.160790, -0.095764,
+0.160217, -0.214607,
+0.158889, -0.304397,
+0.156737, -0.360039,
+0.150208, -0.401271,
+0.124974, -0.427020,
+0.078909, -0.447270,
+0.052876, -0.452784,
+0.038706, -0.454157,
+-0.024785, -0.446256,
+-0.075312, -0.415388,
+-0.091657, -0.396699,
+-0.103874, -0.371529,
+};
index 6baf71b..23d6499 100644 (file)
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <dali-toolkit/dali-toolkit.h>
 #include <dali-physics/dali-physics.h>
+#include <dali-toolkit/dali-toolkit.h>
 
 #include <dali-toolkit/devel-api/visuals/image-visual-properties-devel.h>
 #include <dali-toolkit/devel-api/visuals/visual-properties-devel.h>
 #include <dali/devel-api/events/hit-test-algorithm.h>
 #include <dali/integration-api/debug.h>
 
+#include <chipmunk/chipmunk.h>
 #include <iostream>
 #include <string>
-#include <chipmunk/chipmunk.h>
+#include "letter-a.h"
+#include "letter-d.h"
+#include "letter-i.h"
+#include "letter-l.h"
+#include "split-letter-d.h"
 
 using namespace Dali;
 using namespace Dali::Toolkit::Physics;
@@ -34,8 +39,7 @@ using namespace Dali::Toolkit::Physics;
 Debug::Filter* gPhysicsDemo = Debug::Filter::New(Debug::Concise, false, "LOG_PHYSICS_EXAMPLE");
 #endif
 
-#define GRABBABLE_MASK_BIT (1u << 31)
-cpShapeFilter NOT_GRABBABLE_FILTER = {CP_NO_GROUP, ~GRABBABLE_MASK_BIT, ~GRABBABLE_MASK_BIT};
+const bool DEBUG_STATE{false};
 
 namespace KeyModifier
 {
@@ -53,10 +57,69 @@ enum Key
 };
 }
 
-const std::string BRICK_WALL    = DEMO_IMAGE_DIR "/brick-wall.jpg";
-const std::string BALL_IMAGE    = DEMO_IMAGE_DIR "/blocks-ball.png";
+const std::string LETTER_IMAGES[4] = {
+  DEMO_IMAGE_DIR "/dali-logo-d.png",
+  DEMO_IMAGE_DIR "/dali-logo-a.png",
+  DEMO_IMAGE_DIR "/dali-logo-l.png",
+  DEMO_IMAGE_DIR "/dali-logo-i.png"};
+
+const std::string BRICK_WALL = DEMO_IMAGE_DIR "/brick-wall.jpg";
+const std::string BALL_IMAGE = DEMO_IMAGE_DIR "/blocks-ball.png";
+
+#if defined(_ARCH_ARM_)
+#define DEMO_ICON_DIR "/usr/share/icons"
+#else
+#define DEMO_ICON_DIR DEMO_IMAGE_DIR
+#endif
+
+const std::string BALL_IMAGES[] = {DEMO_IMAGE_DIR "/blocks-ball.png",
+                                   DEMO_ICON_DIR "/dali-tests.png",
+                                   DEMO_ICON_DIR "/dali-examples.png",
+                                   DEMO_ICON_DIR "/com.samsung.dali-demo.png"};
+
+const std::string LOGO          = DEMO_IMAGE_DIR "/Logo-for-demo.png";
 const std::string BRICK_URIS[4] = {
-  DEMO_IMAGE_DIR "/blocks-brick-1.png", DEMO_IMAGE_DIR "/blocks-brick-2.png", DEMO_IMAGE_DIR "/blocks-brick-3.png", DEMO_IMAGE_DIR "/blocks-brick-4.png"};
+  DEMO_IMAGE_DIR "/blocks-brick-1.png",
+  DEMO_IMAGE_DIR "/blocks-brick-2.png",
+  DEMO_IMAGE_DIR "/blocks-brick-3.png",
+  DEMO_IMAGE_DIR "/blocks-brick-4.png"};
+
+using Verts = double*;
+
+const Verts LETTER_VERTICES[] = {&letter_d0[0], &letter_d1[0], &letter_a[0], &letter_l[0], &letter_i[0]};
+//const Verts LETTER_VERTS[4] = {&letter_d[0], &letter_a[0], &letter_l[0], &letter_i[0]};
+const size_t NUMBER_OF_VERTICES[] = {
+  sizeof(letter_d0) / (2 * sizeof(double)),
+  sizeof(letter_d1) / (2 * sizeof(double)),
+  sizeof(letter_a) / (2 * sizeof(double)),
+  sizeof(letter_l) / (2 * sizeof(double)),
+  sizeof(letter_i) / (2 * sizeof(double))};
+
+// Indexed by letter - index into VERTICES / NUMBER_OF_VERTICES arrays
+const std::vector<int> LETTER_SHAPE_INDEXES[]{{0, 1}, {2}, {3}, {4}};
+
+// Groups that can collide with each other:
+const cpGroup BALL_GROUP{1 << 0};
+const cpGroup LETTER_GROUP_1{1 << 1};
+const cpGroup LETTER_GROUP_2{1 << 2};
+const cpGroup LETTER_GROUP_3{1 << 3};
+const cpGroup LETTER_GROUP_4{1 << 4};
+const cpGroup BOUNDS_GROUP{1 << 5};
+
+const cpBitmask COLLISION_MASK{0x3F};
+
+const cpBitmask BALL_COLLIDES_WITH{BALL_GROUP | LETTER_GROUP_1 | LETTER_GROUP_2 | LETTER_GROUP_3 | LETTER_GROUP_4 | BOUNDS_GROUP};
+const cpBitmask LETTER_1_COLLIDES_WITH{BALL_GROUP | LETTER_GROUP_2 | BOUNDS_GROUP};
+const cpBitmask LETTER_2_COLLIDES_WITH{BALL_GROUP | LETTER_GROUP_1 | LETTER_GROUP_3};
+const cpBitmask LETTER_3_COLLIDES_WITH{BALL_GROUP | LETTER_GROUP_2 | LETTER_GROUP_4};
+const cpBitmask LETTER_4_COLLIDES_WITH{BALL_GROUP | LETTER_GROUP_3 | BOUNDS_GROUP};
+
+static cpFloat SpringForce(cpConstraint* spring, cpFloat distance)
+{
+  cpFloat clamp = 20.0f;
+  return cpfclamp(cpDampedSpringGetRestLength(spring) - distance, -clamp, clamp) *
+         cpDampedSpringGetStiffness(spring);
+}
 
 /**
  * @brief The physics demo using Chipmunk2D APIs.
@@ -92,61 +155,189 @@ public:
                                              0.0f));
 
     mPhysicsAdaptor = PhysicsAdaptor::New(mPhysicsTransform, windowSize);
-    mPhysicsRoot = mPhysicsAdaptor.GetRootActor();
+    mPhysicsRoot    = mPhysicsAdaptor.GetRootActor();
     mPhysicsRoot.TouchedSignal().Connect(this, &PhysicsDemoController::OnTouched);
 
     mWindow.Add(mPhysicsRoot);
+    mPopcornTimer = Timer::New(7000);
+    mPopcornTimer.TickSignal().Connect(this, &PhysicsDemoController::OnPopcornTick);
+    mPopcornTimer.Start();
 
-    auto scopedAccessor = mPhysicsAdaptor.GetPhysicsAccessor();
-    cpSpace* space = scopedAccessor->GetNative().Get<cpSpace*>();
+    auto     scopedAccessor = mPhysicsAdaptor.GetPhysicsAccessor();
+    cpSpace* space          = scopedAccessor->GetNative().Get<cpSpace*>();
 
     CreateBounds(space, windowSize);
+
     // Ball area = 2*PI*26^2 ~= 6.28*26*26 ~= 5400
-    // Fill quarter of the screen...
+    // Fill top quarter of the screen...
     int numBalls = 10 + windowSize.GetWidth() * windowSize.GetHeight() / 20000;
     for(int i = 0; i < numBalls; ++i)
     {
-      CreateBall(space);
+      mBalls.push_back(CreateBall(space));
     }
+    //AddSprings(space);
+    //CreateLogo(space);
+    CreateLetters(space);
 
     // For funky mouse drag
     mMouseBody = cpBodyNewKinematic(); // Mouse actor is a kinematic body that is not integrated
 
     // Process any async queued methods next frame
     mPhysicsAdaptor.CreateSyncPoint();
+
+    if(DEBUG_STATE)
+    {
+      mPhysicsDebugLayer = mPhysicsAdaptor.CreateDebugLayer(mWindow);
+      mPhysicsAdaptor.SetDebugState(PhysicsAdaptor::DebugState::ON);
+    }
   }
 
-  void CreateBall(cpSpace* space)
+  PhysicsActor CreateBall(cpSpace* space)
   {
     const float BALL_MASS       = 10.0f;
-    const float BALL_RADIUS     = 26.0f;
+    const float BALL_RADIUS     = 13.0f;
     const float BALL_ELASTICITY = 0.5f;
     const float BALL_FRICTION   = 0.5f;
 
-    auto ball = Toolkit::ImageView::New(BALL_IMAGE);
-
-    cpBody* body = cpSpaceAddBody(space, cpBodyNew(BALL_MASS, cpMomentForCircle(BALL_MASS, 0.0f, BALL_RADIUS, cpvzero)));
+    auto ball                   = Toolkit::ImageView::New(BALL_IMAGES[rand() % 4]);
+    ball[Actor::Property::NAME] = "Ball";
+    ball[Actor::Property::SIZE] = Vector2(26, 26); // Halve the image size
+    cpBody* body                = cpSpaceAddBody(space, cpBodyNew(BALL_MASS, cpMomentForCircle(BALL_MASS, 0.0f, BALL_RADIUS, cpvzero)));
 
     cpShape* shape = cpSpaceAddShape(space, cpCircleShapeNew(body, BALL_RADIUS, cpvzero));
     cpShapeSetElasticity(shape, BALL_ELASTICITY);
     cpShapeSetFriction(shape, BALL_FRICTION);
-
+    //cpShapeSetFilter(shape, cpShapeFilterNew(BALL_GROUP, BALL_COLLIDES_WITH, COLLISION_MASK));
     ball.RegisterProperty("uBrightness", 0.0f);
 
     PhysicsActor physicsBall = mPhysicsAdaptor.AddActorBody(ball, body);
 
-    Window::WindowSize windowSize  = mWindow.GetSize();
+    Window::WindowSize windowSize = mWindow.GetSize();
 
-    const float        fw          = 0.5f*(windowSize.GetWidth() - BALL_RADIUS);
-    const float        fh          = 0.5f*(windowSize.GetHeight() - BALL_RADIUS);
+    const float fw = 0.5f * (windowSize.GetWidth() - BALL_RADIUS);
+    const float fh = 0.5f * (windowSize.GetHeight() - BALL_RADIUS);
 
     // Example of setting physics property on update thread
-    physicsBall.AsyncSetPhysicsPosition(Vector3(Random::Range(-fw, fw), Random::Range(-fh, fh), 0.0f));
+    physicsBall.AsyncSetPhysicsPosition(Vector3(Random::Range(-fw, fw), Random::Range(-fh, -fh * 0.5), 0.0f));
 
     // Example of queuing a chipmunk method to run on the update thread
-    mPhysicsAdaptor.Queue([body](){
+    mPhysicsAdaptor.Queue([body]() {
       cpBodySetVelocity(body, cpv(Random::Range(-100.0, 100.0), Random::Range(-100.0, 100.0)));
     });
+    return physicsBall;
+  }
+
+  void CreateLogo(cpSpace* space)
+  {
+    const float MASS = 20.0f;
+    auto        logo = Toolkit::ImageView::New(LOGO);
+    Vector2     logoSize{368, 208};
+    logo[Actor::Property::SIZE] = logoSize; // Double in size
+
+    cpBody*      logoBody  = cpSpaceAddBody(space, cpBodyNew(MASS, cpMomentForBox(MASS, logoSize.width, logoSize.height)));
+    cpShape*     logoShape = cpSpaceAddShape(space, cpBoxShapeNew(logoBody, logoSize.width, logoSize.height, 0.0));
+    PhysicsActor logoActor = mPhysicsAdaptor.AddActorBody(logo, logoBody);
+
+    cpShapeSetFriction(logoShape, 0.9);
+    cpShapeSetElasticity(logoShape, 0.0);
+    Window::WindowSize windowSize = mWindow.GetSize();
+    Vector3            daliPos(0, -windowSize.GetHeight() / 2 + logoSize.height * 1.3, 0);
+    Vector3            physPos = mPhysicsAdaptor.TranslateToPhysicsSpace(daliPos);
+    cpBodySetPosition(logoBody, cpv(physPos.x, physPos.y));
+
+    cpBody*       staticBody = cpSpaceGetStaticBody(space);
+    cpConstraint* spring     = NewSpring(staticBody, logoBody, cpv(0, 0), cpv(0, logoSize.height / 2));
+    cpSpaceAddConstraint(space, spring);
+  }
+
+  void CreateLetters(cpSpace* space)
+  {
+    const float LETTER_MASS = 10.0f;
+    const float RADIUS      = 85.0f;
+    const float ELASTICITY  = 0.0f;
+    const float FRICTION    = 0.9f;
+
+    static const cpShapeFilter FILTERS[4] = {
+      cpShapeFilterNew(LETTER_GROUP_1, LETTER_1_COLLIDES_WITH, COLLISION_MASK),
+      cpShapeFilterNew(LETTER_GROUP_2, LETTER_2_COLLIDES_WITH, COLLISION_MASK),
+      cpShapeFilterNew(LETTER_GROUP_3, LETTER_3_COLLIDES_WITH, COLLISION_MASK),
+      cpShapeFilterNew(LETTER_GROUP_4, LETTER_4_COLLIDES_WITH, COLLISION_MASK)};
+
+    static const std::string NAME[4] = {"d", "a", "l", "i"};
+    for(int index = 0; index < 4; ++index)
+    {
+      auto letter                   = Toolkit::ImageView::New(LETTER_IMAGES[index]);
+      letter[Actor::Property::NAME] = NAME[index];
+
+      cpBody* body = cpSpaceAddBody(space, cpBodyNew(LETTER_MASS, cpMomentForCircle(LETTER_MASS, 0.0f, RADIUS, cpvzero)));
+
+      for(size_t letterShapeIndex = 0; letterShapeIndex < LETTER_SHAPE_INDEXES[index].size(); ++letterShapeIndex)
+      {
+        size_t shapeIndex = LETTER_SHAPE_INDEXES[index][letterShapeIndex];
+
+        std::vector<cpVect> scaledVerts;
+        size_t              numberOfElements = NUMBER_OF_VERTICES[shapeIndex];
+        scaledVerts.resize(numberOfElements);
+        for(size_t i = 0; i < numberOfElements; ++i)
+        {
+          double x       = LETTER_VERTICES[shapeIndex][i * 2 + 0];
+          double y       = LETTER_VERTICES[shapeIndex][i * 2 + 1];
+          scaledVerts[i] = cpv(x * 122.0f, y * 171.0f); // Verts are normalized to +-0.5
+        }
+        cpFloat bevel = 1.0;
+
+        cpShape* shape = cpSpaceAddShape(space, cpPolyShapeNew(body, numberOfElements, &scaledVerts[0], cpTransformIdentity, bevel));
+        cpShapeSetElasticity(shape, ELASTICITY);
+        cpShapeSetFriction(shape, FRICTION);
+        cpShapeSetFilter(shape, FILTERS[index]);
+      }
+
+      PhysicsActor physicsLetter = mPhysicsAdaptor.AddActorBody(letter, body);
+
+      Window::WindowSize windowSize = mWindow.GetSize();
+
+      // Image is 326x171; center of letter is guessed; each image contains only 1 image.
+      // Position the letters into the window
+
+      float   cellW   = (windowSize.GetWidth() - 170) / 4;
+      float   cellC   = -windowSize.GetWidth() * 0.5f + cellW * (0.5f + index);
+      float   x       = 85 + cellC; // - 61.0f;
+      Vector3 physPos = mPhysicsAdaptor.TranslateToPhysicsSpace(Vector3(x, 0, 0.0f));
+
+      // Have to set position before setting constraint
+      cpBodySetPosition(body, cpv(physPos.x, physPos.y));
+
+      // Add a fixed pivot at top of shape
+      cpBody* staticBody = cpSpaceGetStaticBody(space);
+
+      Vector3 localPivot(x, -70.0f, 0.0f);
+      Vector3 pivotPhys = mPhysicsAdaptor.TranslateToPhysicsSpace(localPivot);
+      cpSpaceAddConstraint(space, cpPivotJointNew(staticBody, body, cpv(pivotPhys.x, pivotPhys.y)));
+    }
+  }
+
+  cpConstraint* NewSpring(cpBody* body1, cpBody* body2, cpVect anchor1, cpVect anchor2)
+  {
+    const cpFloat STIFFNESS{100.0f};
+    const cpFloat DAMPING{0.5f};
+    cpConstraint* spring = cpDampedSpringNew(body1, body2, anchor1, anchor2, 0.0f, STIFFNESS, DAMPING);
+    cpDampedSpringSetSpringForceFunc(spring, SpringForce);
+    return spring;
+  }
+
+  void AddSprings(cpSpace* space)
+  {
+    int N         = mBalls.size();
+    int randValue = 3 + rand() % (N / 4); // Some number of pairs
+    for(int i = 0; i < randValue; ++i)
+    {
+      int     randIndex = rand() % N;
+      cpBody* body1     = mBalls[randIndex].GetBody().Get<cpBody*>();
+      cpBody* body2     = mBalls[(randIndex + 1) % N].GetBody().Get<cpBody*>();
+
+      cpConstraint* spring = NewSpring(body1, body2, cpv(25, 0), cpv(-25, 0));
+      cpSpaceAddConstraint(space, spring);
+    }
   }
 
   void CreateBounds(cpSpace* space, Window::WindowSize size)
@@ -180,7 +371,7 @@ public:
     cpShapeSetElasticity(shape, 1.0f);
     cpShapeSetFriction(shape, 1.0f);
 
-    cpShapeSetFilter(shape, NOT_GRABBABLE_FILTER);
+    cpShapeSetFilter(shape, cpShapeFilterNew(BOUNDS_GROUP, COLLISION_MASK, COLLISION_MASK));
     return shape;
   }
 
@@ -209,12 +400,30 @@ public:
 
   void OnWindowResize(Window window, Window::WindowSize newSize)
   {
-    auto scopedAccessor = mPhysicsAdaptor.GetPhysicsAccessor();
-    cpSpace* space = scopedAccessor->GetNative().Get<cpSpace*>();
+    auto     scopedAccessor = mPhysicsAdaptor.GetPhysicsAccessor();
+    cpSpace* space          = scopedAccessor->GetNative().Get<cpSpace*>();
 
     CreateBounds(space, newSize);
   }
 
+  bool OnPopcornTick()
+  {
+    auto scopedAccessor = mPhysicsAdaptor.GetPhysicsAccessor();
+
+    // fire off N random balls upwards with a high impulse
+    int N         = mBalls.size();
+    int randValue = 10 + rand() % (N / 2);
+
+    for(int i = 0; i < randValue; ++i)
+    {
+      int     randIndex = rand() % N;
+      cpBody* body      = mBalls[randIndex].GetBody().Get<cpBody*>();
+      cpBodyActivate(body);
+      cpBodyApplyImpulseAtLocalPoint(body, cpv(rand() % 200 - 100, -10000), cpv(0, 25));
+    }
+    return true;
+  }
+
   bool OnTouched(Dali::Actor actor, const Dali::TouchEvent& touch)
   {
     static enum {
@@ -225,7 +434,7 @@ public:
     auto renderTask   = mWindow.GetRenderTaskList().GetTask(0);
     auto screenCoords = touch.GetScreenPosition(0);
     // In this demo, physics space is equivalent to screen space with y inverted
-    auto windowSize = mWindow.GetSize();
+    auto    windowSize = mWindow.GetSize();
     Vector3 rayPhysicsOrigin(screenCoords.x, windowSize.GetHeight() - screenCoords.y, 0.0f);
 
     switch(state)
@@ -236,17 +445,24 @@ public:
         {
           state = MovePivot;
 
-          auto scopedAccessor = mPhysicsAdaptor.GetPhysicsAccessor();
-          cpSpace* space = scopedAccessor->GetNative().Get<cpSpace*>();
+          auto     scopedAccessor = mPhysicsAdaptor.GetPhysicsAccessor();
+          cpSpace* space          = scopedAccessor->GetNative().Get<cpSpace*>();
 
           Vector3 localPivot;
           float   pickingDistance;
 
-          auto body = scopedAccessor->HitTest(rayPhysicsOrigin, rayPhysicsOrigin, localPivot, pickingDistance);
+          cpShapeFilter ballFilter{CP_NO_GROUP, 1u << 31, 1u << 31};
+          auto          body = scopedAccessor->HitTest(rayPhysicsOrigin, rayPhysicsOrigin, ballFilter, localPivot, pickingDistance);
+          if(body.Empty())
+          {
+            cpShapeFilter letterFilter{CP_NO_GROUP, COLLISION_MASK, COLLISION_MASK};
+            body = scopedAccessor->HitTest(rayPhysicsOrigin, rayPhysicsOrigin, letterFilter, localPivot, pickingDistance);
+          }
           if(!body.Empty())
           {
-            mPickedBody = body.Get<cpBody*>();
+            mPickedBody    = body.Get<cpBody*>();
             mSelectedActor = mPhysicsAdaptor.GetPhysicsActor(mPickedBody);
+            std::cout << "PhysicsActor: " << mPhysicsAdaptor.GetRootActor().FindChildById(mSelectedActor.GetId()).GetProperty<std::string>(Actor::Property::NAME) << std::endl;
 
             mPickedSavedState = cpBodyIsSleeping(mPickedBody);
             cpBodyActivate(mPickedBody);
@@ -273,8 +489,8 @@ public:
         {
           if(mPickedConstraint)
           {
-            auto scopedAccessor = mPhysicsAdaptor.GetPhysicsAccessor();
-            cpSpace* space = scopedAccessor->GetNative().Get<cpSpace*>();
+            auto     scopedAccessor = mPhysicsAdaptor.GetPhysicsAccessor();
+            cpSpace* space          = scopedAccessor->GetNative().Get<cpSpace*>();
 
             if(mPickedSavedState)
             {
@@ -296,7 +512,6 @@ public:
       }
     }
 
-
     Stage::GetCurrent().KeepRendering(30.0f);
 
     return true;
@@ -305,6 +520,7 @@ public:
   void OnKeyEv(const Dali::KeyEvent& event)
   {
     static bool integrateState{true};
+    static bool debugState{DEBUG_STATE};
 
     if(event.GetState() == KeyEvent::DOWN)
     {
@@ -336,11 +552,17 @@ public:
           }
           else if(!event.GetKeyString().compare(" "))
           {
-            integrateState = true^integrateState;
-            mPhysicsAdaptor.SetIntegrationState(integrateState?
-                                                PhysicsAdaptor::IntegrationState::ON:
-                                                PhysicsAdaptor::IntegrationState::OFF);
-
+            integrateState = true ^ integrateState;
+            mPhysicsAdaptor.SetIntegrationState(integrateState ? PhysicsAdaptor::IntegrationState::ON : PhysicsAdaptor::IntegrationState::OFF);
+          }
+          else if(!event.GetKeyString().compare("m"))
+          {
+            debugState = true ^ debugState;
+            if(debugState && !mPhysicsDebugLayer)
+            {
+              mPhysicsDebugLayer = mPhysicsAdaptor.CreateDebugLayer(mWindow);
+            }
+            mPhysicsAdaptor.SetDebugState(debugState ? PhysicsAdaptor::DebugState::ON : PhysicsAdaptor::DebugState::OFF);
           }
           else if(!event.GetKeyString().compare("w"))
           {
@@ -391,10 +613,13 @@ public:
             // Rotate anti-clockwise
             if(mSelectedActor)
             {
-              Quaternion quaternion = mSelectedActor.GetActorRotation();
-              quaternion *= Quaternion(Degree(-15.0f), Vector3::ZAXIS);
-              mSelectedActor.AsyncSetPhysicsRotation(quaternion);
-              cpBody* body = mSelectedActor.GetBody().Get<cpBody*>();
+              // A negative angle should rotate anti-clockwise, which it does,
+              // BUT, we mirror in Y axis, so actually, it LOOKS like it rotates clockwise.
+              // So, we have to invert angle.
+
+              cpBody* body  = mSelectedActor.GetBody().Get<cpBody*>();
+              float   angle = cpBodyGetAngle(body);
+              mPhysicsAdaptor.Queue([body, angle]() { cpBodySetAngle(body, angle + Math::PI / 12.0f); });
               mPhysicsAdaptor.Queue([body]() { cpBodyActivate(body); });
               mPhysicsAdaptor.CreateSyncPoint();
             }
@@ -404,9 +629,9 @@ public:
             // Rotate clockwise using native physics APIs
             if(mSelectedActor)
             {
-              cpBody* body = mSelectedActor.GetBody().Get<cpBody*>();
-              float angle = cpBodyGetAngle(body);
-              mPhysicsAdaptor.Queue([body, angle]() { cpBodySetAngle(body, angle-Math::PI/12.0f); });
+              cpBody* body  = mSelectedActor.GetBody().Get<cpBody*>();
+              float   angle = cpBodyGetAngle(body);
+              mPhysicsAdaptor.Queue([body, angle]() { cpBodySetAngle(body, angle - Math::PI / 12.0f); });
               mPhysicsAdaptor.Queue([body]() { cpBodyActivate(body); });
               mPhysicsAdaptor.CreateSyncPoint();
             }
@@ -445,14 +670,19 @@ private:
   Application& mApplication;
   Window       mWindow;
 
-  PhysicsAdaptor mPhysicsAdaptor;
-  PhysicsActor   mSelectedActor;
-  Matrix        mPhysicsTransform;
-  Actor         mPhysicsRoot;
-  cpBody*       mMouseBody{nullptr};
-  cpBody*       mPickedBody{nullptr};
-  cpConstraint* mPickedConstraint{nullptr};
-  int           mPickedSavedState = -1; /// 0 : Active, 1 : Sleeping
+  PhysicsAdaptor            mPhysicsAdaptor;
+  PhysicsActor              mSelectedActor;
+  std::vector<PhysicsActor> mBalls;
+  Matrix                    mPhysicsTransform;
+  Actor                     mPhysicsRoot;
+  Layer                     mPhysicsDebugLayer;
+  cpBody*                   mMouseBody{nullptr};
+  cpBody*                   mPickedBody{nullptr};
+  cpConstraint*             mPickedConstraint{nullptr};
+  int                       mPickedSavedState = -1; /// 0 : Active, 1 : Sleeping
+  Timer                     mPopcornTimer;
+
+  PhysicsAdaptor::DebugState mDebugState{PhysicsAdaptor::DebugState::OFF};
 
   cpShape* mLeftBound{nullptr};
   cpShape* mRightBound{nullptr};
diff --git a/examples/chipmunk-physics/split-letter-d.h b/examples/chipmunk-physics/split-letter-d.h
new file mode 100644 (file)
index 0000000..ab0572d
--- /dev/null
@@ -0,0 +1,68 @@
+double letter_d0[] = {
+0.131136, -0.445716,
+0.210390, -0.423237,
+0.262577, -0.399065,
+0.303066, -0.375918,
+0.337334, -0.354157,
+0.351012, -0.340831,
+0.375016, -0.322534,
+0.396490, -0.293488,
+0.416732, -0.270408,
+0.434497, -0.237234,
+0.201921, 0.161833,
+0.184565, 0.165839,
+0.162353, 0.175720,
+0.127279, 0.187103,
+0.077452, 0.195250,
+0.014636, 0.197297,
+-0.055010, 0.192870,
+-0.121485, 0.183899,
+-0.176149, 0.172829,
+-0.216299, 0.161038,
+-0.245481, 0.148720,
+-0.271343, 0.135014,
+-0.299749, 0.118339,
+-0.333036, 0.096502,
+-0.370072, 0.066624,
+-0.407117, 0.024452,
+-0.438623, -0.036298,
+-0.457155, -0.123895,
+-0.443017, -0.239761,
+-0.333914, -0.370416,
+-0.238509, -0.415552,
+-0.143103, -0.447210,
+-0.015264, -0.458859,
+};
+double letter_d1[] = {
+0.201921, 0.166840,
+0.202679, 0.182716,
+0.201478, 0.209592,
+0.200000, 0.245338,
+0.199170, 0.285514,
+0.199298, 0.324164,
+0.200628, 0.356920,
+0.203567, 0.382294,
+0.208675, 0.401603,
+0.216465, 0.417345,
+0.227141, 0.431093,
+0.240564, 0.443229,
+0.256365, 0.453172,
+0.274400, 0.460291,
+0.294957, 0.464321,
+0.318714, 0.465354,
+0.345982, 0.463514,
+0.375657, 0.458505,
+0.405080, 0.449557,
+0.430514, 0.435231,
+0.449290, 0.412602,
+0.463973, 0.370117,
+0.466592, 0.321481,
+0.468970, 0.241971,
+0.469557, 0.141277,
+0.468917, 0.030611,
+0.466712, -0.072655,
+0.462341, -0.155056,
+0.452636, -0.199979,
+0.434497, -0.237234,
+0.201921, 0.161833,
+};
diff --git a/resources/images/dali-logo-a.png b/resources/images/dali-logo-a.png
new file mode 100644 (file)
index 0000000..3e8a377
Binary files /dev/null and b/resources/images/dali-logo-a.png differ
diff --git a/resources/images/dali-logo-d.png b/resources/images/dali-logo-d.png
new file mode 100644 (file)
index 0000000..0153a93
Binary files /dev/null and b/resources/images/dali-logo-d.png differ
diff --git a/resources/images/dali-logo-i.png b/resources/images/dali-logo-i.png
new file mode 100644 (file)
index 0000000..3f5afa5
Binary files /dev/null and b/resources/images/dali-logo-i.png differ
diff --git a/resources/images/dali-logo-l.png b/resources/images/dali-logo-l.png
new file mode 100644 (file)
index 0000000..d57ad58
Binary files /dev/null and b/resources/images/dali-logo-l.png differ