Merge "Apply fittingMode lazy when resource is not ready" into devel/master
authorsunghyun kim <scholb.kim@samsung.com>
Mon, 11 Sep 2023 00:55:26 +0000 (00:55 +0000)
committerGerrit Code Review <gerrit@review>
Mon, 11 Sep 2023 00:55:26 +0000 (00:55 +0000)
24 files changed:
automated-tests/src/dali-physics2d/utc-Dali-PhysicsActor.cpp
automated-tests/src/dali-physics2d/utc-Dali-PhysicsAdaptor.cpp
automated-tests/src/dali-physics3d/utc-Dali-PhysicsAdaptor.cpp
build/tizen/dali-physics/CMakeLists.txt
dali-physics/internal/bullet-impl/bullet-physics-world-impl.cpp
dali-physics/internal/bullet-impl/bullet-physics-world-impl.h
dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.cpp
dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.h
dali-physics/internal/chipmunk-impl/chipmunk-physics-debug-renderer.cpp [new file with mode: 0644]
dali-physics/internal/chipmunk-impl/chipmunk-physics-debug-renderer.h [new file with mode: 0644]
dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.cpp
dali-physics/internal/chipmunk-impl/chipmunk-physics-world-impl.h
dali-physics/internal/file.list
dali-physics/internal/physics-world-impl.cpp
dali-physics/internal/physics-world-impl.h
dali-physics/public-api/physics-adaptor.h
dali-physics/public-api/scoped-physics-accessor.cpp
dali-physics/third-party/chipmunk2d/include/chipmunk/cpBody.h
dali-physics/third-party/chipmunk2d/include/chipmunk/cpShape.h
dali-physics/third-party/chipmunk2d/src/CMakeLists.txt
dali-physics/third-party/chipmunk2d/src/cpBody.c
dali-physics/third-party/chipmunk2d/src/cpShape.c
dali-toolkit/public-api/dali-toolkit-version.cpp
packaging/dali-toolkit.spec

index 855d686..91700fd 100644 (file)
@@ -372,7 +372,7 @@ int UtcDaliPhysics2DActorSetRotation1(void)
     // Warning - physics properties are never reflected in the event size cache.
     // Have to use GetCurrentProperty to see the updated values.
     Quaternion q = actor.GetCurrentProperty<Quaternion>(Actor::Property::ORIENTATION);
-    Quaternion expected(Degree(30), Vector3::ZAXIS);
+    Quaternion expected(Degree(-30), Vector3::ZAXIS);
     DALI_TEST_EQUALS(q, expected, 0.0001f, TEST_LOCATION);
   }
 
@@ -385,7 +385,7 @@ int UtcDaliPhysics2DActorSetRotation2(void)
 
   ToolkitTestApplication application;
   Matrix                 transform(false);
-  transform.SetIdentityAndScale(Vector3(2.0f, -2.0f, 1.0f));
+  transform.SetIdentityAndScale(Vector3(2.0f, 2.0f, 1.0f));
   Uint16Pair     size(640, 480);
   PhysicsAdaptor adaptor   = PhysicsAdaptor::New(transform, size);
   Actor          rootActor = adaptor.GetRootActor();
index b6ca868..cf846bb 100644 (file)
@@ -60,6 +60,49 @@ cpBody* CreateBody(cpSpace* space)
   return body;
 }
 
+// Defines a PolyShape
+cpBody* CreateHexBody(cpSpace* space)
+{
+  const float MASS       = 10.0f;
+  const float RADIUS     = 26.0f;
+  const float ELASTICITY = 0.5f;
+  const float FRICTION   = 0.5f;
+
+  cpVect hexagon[6];
+  for(int i = 0; i < 6; i++)
+  {
+    cpFloat angle = -CP_PI * 2.0f * i / 6.0f;
+    hexagon[i]    = cpvmult(cpv(cos(angle), sin(angle)), RADIUS - 1.0f);
+  }
+
+  cpBody*  body  = cpSpaceAddBody(space, cpBodyNew(MASS, cpMomentForPoly(MASS, 6, hexagon, cpvzero, 0.0f)));
+  cpShape* shape = cpSpaceAddShape(space, cpPolyShapeNew(body, 6, hexagon, cpTransformIdentity, 1.0f));
+
+  cpShapeSetElasticity(shape, ELASTICITY);
+  cpShapeSetFriction(shape, FRICTION);
+
+  return body;
+}
+
+// Defines a SegmentShape
+cpBody* CreateSegBody(cpSpace* space)
+{
+  const float MASS       = 10.0f;
+  const float RADIUS     = 26.0f;
+  const float ELASTICITY = 0.5f;
+  const float FRICTION   = 0.5f;
+
+  cpVect   a     = cpv(0, 100);
+  cpVect   b     = cpv(100, 0);
+  cpBody*  body  = cpSpaceAddBody(space, cpBodyNew(MASS, cpMomentForSegment(MASS, a, b, 0.0f)));
+  cpShape* shape = cpSpaceAddShape(space, cpSegmentShapeNew(body, a, b, RADIUS));
+
+  cpShapeSetElasticity(shape, ELASTICITY);
+  cpShapeSetFriction(shape, FRICTION);
+
+  return body;
+}
+
 int UtcDaliPhysics2DCreateAdaptorP1(void)
 {
   ToolkitTestApplication application;
@@ -290,7 +333,46 @@ int UtcDaliPhysics2DAdaptorCreateDebugLayer(void)
   Window window = DevelWindow::Get(rootActor);
 
   Layer layer = adaptor.CreateDebugLayer(window);
-  DALI_TEST_CHECK(!layer);
+  DALI_TEST_CHECK(layer);
+
+  adaptor.SetDebugState(PhysicsAdaptor::DebugState::ON);
+
+  cpBody* body{nullptr};
+  cpBody* body2{nullptr};
+  cpBody* body3{nullptr};
+  {
+    auto accessor = adaptor.GetPhysicsAccessor();
+    auto space    = accessor->GetNative().Get<cpSpace*>();
+
+    body                     = CreateBody(space);
+    Dali::Actor ballActor    = Toolkit::ImageView::New("gallery-small-1.jpg");
+    auto        physicsActor = adaptor.AddActorBody(ballActor, body);
+    cpBodySetPosition(body, cpv(0, 0));
+
+    // Constraint should create a dot in debug
+    cpBody* staticBody = cpSpaceGetStaticBody(space);
+    cpSpaceAddConstraint(space, cpPivotJointNew(staticBody, body, cpv(10, 10)));
+
+    body2                     = CreateHexBody(space);
+    Dali::Actor ballActor2    = Toolkit::ImageView::New("gallery-small-1.jpg");
+    auto        physicsActor2 = adaptor.AddActorBody(ballActor2, body2);
+    cpBodySleep(body2);
+
+    body3                     = CreateSegBody(space);
+    Dali::Actor ballActor3    = Toolkit::ImageView::New("gallery-small-1.jpg");
+    auto        physicsActor3 = adaptor.AddActorBody(ballActor3, body3);
+  }
+  Test::WaitForEventThreadTrigger(1);
+
+  // Render - if it doesn't crash, great!
+  application.SendNotification();
+  application.Render();
+
+  Uint16Pair size2(480, 640);
+  adaptor.SetTransformAndSize(transform, size2);
+
+  application.SendNotification();
+  application.Render();
 
   END_TEST;
 }
@@ -321,7 +403,8 @@ int UtcDaliPhysics2DAdaptorTranslateToPhysicsSpace2(void)
 
   // Rotation shouldn't change under this scale
   Quaternion q(Degree(30.0f), Vector3::XAXIS);
-  DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), q, 0.0001f, TEST_LOCATION);
+  Quaternion expected(Degree(30.0f), Vector3::XAXIS);
+  DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), expected, 0.0001f, TEST_LOCATION);
 
   END_TEST;
 }
@@ -330,52 +413,16 @@ int UtcDaliPhysics2DAdaptorTranslateToPhysicsSpace3(void)
 {
   ToolkitTestApplication application;
   Matrix                 transform(false);
-  tet_infoline("Test that using an inverted Y scale does nothing to rotation");
+  tet_infoline("Test that using an inverted Y scale inverts rotation");
 
   transform.SetIdentityAndScale(Vector3(1.0f, -1.0f, 1.0f));
   Uint16Pair     size(640, 480);
   PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
 
   Quaternion q(Degree(30.0f), Vector3::ZAXIS);
-  Quaternion qp(Degree(30.0f), Vector3::ZAXIS);
-
-  DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), qp, 0.0001f, TEST_LOCATION);
-
-  END_TEST;
-}
-
-int UtcDaliPhysics2DAdaptorTranslateToPhysicsSpace4(void)
-{
-  ToolkitTestApplication application;
-  Matrix                 transform(false);
-  tet_infoline("Test that using an inverted Y scale does nothing to rotation");
-
-  transform.SetIdentityAndScale(Vector3(1.0f, -1.0f, 1.0f));
-  Uint16Pair     size(640, 480);
-  PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
+  Quaternion expected(Degree(-30.0f), Vector3::ZAXIS);
 
-  Quaternion q(Degree(30.0f), Vector3::XAXIS);
-  Quaternion qp(Degree(30.0f), Vector3::XAXIS);
-
-  DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), qp, 0.0001f, TEST_LOCATION);
-
-  END_TEST;
-}
-
-int UtcDaliPhysics2DAdaptorTranslateToPhysicsSpace5(void)
-{
-  ToolkitTestApplication application;
-  Matrix                 transform(false);
-  tet_infoline("Test that using an inverted Y scale does nothing to rotation");
-
-  transform.SetIdentityAndScale(Vector3(1.0f, -1.0f, 1.0f));
-  Uint16Pair     size(640, 480);
-  PhysicsAdaptor adaptor = PhysicsAdaptor::New(transform, size);
-
-  Quaternion q(Degree(30.0f), Vector3::YAXIS);
-  Quaternion qp(Degree(30.0f), Vector3::YAXIS);
-
-  DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), qp, 0.0001f, TEST_LOCATION);
+  DALI_TEST_EQUALS(adaptor.TranslateToPhysicsSpace(q), expected, 0.0001f, TEST_LOCATION);
 
   END_TEST;
 }
@@ -926,7 +973,11 @@ int UtcDaliPhysics2DAdaptorHitTestP(void)
     auto    accessor = adaptor.GetPhysicsAccessor();
     Vector3 localPivot;
     float   distanceFromCamera;
-    auto    body = accessor->HitTest(from, from, localPivot, distanceFromCamera);
+
+    cpShapeFilter GRAB_FILTER = {CP_NO_GROUP, 1u << 31, 1u << 31};
+    Dali::Any     nativeFilter{GRAB_FILTER};
+
+    auto body = accessor->HitTest(from, from, nativeFilter, localPivot, distanceFromCamera);
 
     DALI_TEST_CHECK(!body.Empty());
   }
index b09c8fc..1315a55 100644 (file)
@@ -947,10 +947,11 @@ int UtcDaliPhysics3DAdaptorHitTestP(void)
   adaptor.BuildPickingRay(origin, direction, from, to); // Hit test centre of screen
 
   {
-    auto    accessor = adaptor.GetPhysicsAccessor();
-    Vector3 localPivot;
-    float   distanceFromCamera;
-    auto    body = accessor->HitTest(from, to, localPivot, distanceFromCamera);
+    auto      accessor = adaptor.GetPhysicsAccessor();
+    Vector3   localPivot;
+    float     distanceFromCamera;
+    Dali::Any nullFilter;
+    auto      body = accessor->HitTest(from, to, nullFilter, localPivot, distanceFromCamera);
 
     DALI_TEST_CHECK(!body.Empty());
   }
index 00c482b..9c52173 100644 (file)
@@ -75,9 +75,12 @@ include(${physics_dir}/public-api/file.list)
 include(${physics_dir}/internal/file.list)
 
 set(prefix_include_dir "${prefix}/include")
-include_directories(${repo_root_dir}
+
+include_directories(BEFORE
+  ${repo_root_dir}
   "${prefix_include_dir}"
   "${repo_root_dir}/dali-physics/third-party/bullet3/src"
+  "${repo_root_dir}/dali-physics/third-party/chipmunk2d/include"
 )
 
 MESSAGE(STATUS "2D sources: ${physics2d_src_files}")
index 79d97de..920d015 100644 (file)
@@ -114,7 +114,7 @@ inline btVector3 ConvertVector(Dali::Vector3 vector)
   return btVector3(vector.x, vector.y, vector.z);
 }
 
-Dali::Any BulletPhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera)
+Dali::Any BulletPhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera)
 {
   btRigidBody* hitBody{nullptr};
 
index 2a5ff55..5f9f193 100644 (file)
@@ -48,11 +48,12 @@ public:
    *
    * @param[in] rayFromWorld The origin in physics world space
    * @param[in] rayToWorld A point along the direction on the far side of the physics world
+   * @param[in] nativeFilter A native shape/body filter
    * @param[out] localPivot The hit point local to the body
    * @param[out] distanceFromCamera The distance of the pick point from the camera
    * @return Empty value if no dynamic body found, otherwise a valid ptr to the hit body.
    */
-  Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) override;
+  Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera) override;
 
   void Integrate(float timestep) override;
 
index 1a4ffb9..923927a 100644 (file)
@@ -71,7 +71,42 @@ void ChipmunkPhysicsAdaptor::OnInitialize(const Dali::Matrix& transform, Uint16P
 
 Layer ChipmunkPhysicsAdaptor::CreateDebugLayer(Dali::Window window)
 {
-  return Layer();
+  Layer debugLayer;
+
+  auto renderTaskList = window.GetRenderTaskList();
+  auto renderTask     = renderTaskList.GetTask(0);
+  auto windowSize     = window.GetSize();
+
+  debugLayer                                 = Layer::New();
+  debugLayer[Actor::Property::NAME]          = "PhysicsDebugLayer";
+  debugLayer[Actor::Property::ANCHOR_POINT]  = Dali::AnchorPoint::CENTER;
+  debugLayer[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER;
+
+  Constraint positionConstraint = Constraint::New<Vector3>(debugLayer, Actor::Property::POSITION, EqualToConstraint());
+  positionConstraint.AddSource(Source(mRootActor, Actor::Property::POSITION));
+  positionConstraint.Apply();
+  Constraint sizeConstraint = Constraint::New<Vector2>(debugLayer, Actor::Property::SIZE, EqualToConstraint());
+  sizeConstraint.AddSource(Source(mRootActor, Actor::Property::SIZE));
+  sizeConstraint.Apply();
+
+  auto world = static_cast<ChipmunkPhysicsWorld*>(mPhysicsWorld.get());
+
+  std::unique_ptr<PhysicsDebugRenderer> debugRenderer = PhysicsDebugRenderer::New(windowSize.GetWidth(), windowSize.GetHeight(), renderTask.GetCameraActor(), this);
+
+  mDebugActor = DrawableActor::New(*(debugRenderer->GetCallback().get()));
+  world->SetDebugRenderer(debugRenderer.release());
+
+  mDebugActor[Actor::Property::ANCHOR_POINT]  = Dali::AnchorPoint::CENTER;
+  mDebugActor[Actor::Property::PARENT_ORIGIN] = Dali::ParentOrigin::CENTER;
+
+  Constraint sizeConstraint2 = Constraint::New<Vector2>(mDebugActor, Actor::Property::SIZE, EqualToConstraint());
+  sizeConstraint2.AddSource(ParentSource(Actor::Property::SIZE));
+  sizeConstraint2.Apply();
+
+  debugLayer.Add(mDebugActor);
+
+  window.Add(debugLayer);
+  return debugLayer;
 }
 
 void ChipmunkPhysicsAdaptor::SetTransformAndSize(const Dali::Matrix& transform, Uint16Pair worldSize)
@@ -82,6 +117,14 @@ void ChipmunkPhysicsAdaptor::SetTransformAndSize(const Dali::Matrix& transform,
   mSize = worldSize;
 
   GetRootActor()[Actor::Property::SIZE] = Vector3(worldSize.GetWidth(), worldSize.GetHeight(), 0);
+
+  auto world = static_cast<ChipmunkPhysicsWorld*>(mPhysicsWorld.get());
+  if(world->HasDebugRenderer())
+  {
+    Actor layer                  = mDebugActor.GetParent();
+    layer[Actor::Property::SIZE] = Vector3(worldSize);
+    world->GetDebugRenderer().UpdateWindowSize(worldSize);
+  }
 }
 
 PhysicsActorPtr ChipmunkPhysicsAdaptor::AddActorBody(Dali::Actor actor, Dali::Any body)
@@ -144,8 +187,22 @@ Vector3 ChipmunkPhysicsAdaptor::TranslateFromPhysicsSpace(Vector3 vector) const
 
 Quaternion ChipmunkPhysicsAdaptor::TranslateToPhysicsSpace(Quaternion orientation) const
 {
-  // It's complicated.
-  return orientation;
+  // Actors face outwards (+ve Z)
+  // In DALi world, +ve angle about +ve Z is clockwise.
+  // But, if physics is mirrored in Y axis, so +ve angle is anti-clockwise.
+
+  // Compute angle about Z axis
+  Vector3 axis;
+  Radian  angle;
+  orientation.ToAxisAngle(axis, angle);
+
+  // Check if Transform matrix is mirrored in X xor Y
+  if(std::signbit(mTransform.AsFloat()[0]) ^ std::signbit(mTransform.AsFloat()[5]))
+  {
+    return Quaternion(-angle, axis);
+  }
+
+  return Quaternion(angle, axis);
 }
 
 Quaternion ChipmunkPhysicsAdaptor::TranslateFromPhysicsSpace(Quaternion orientation) const
index 48715e3..55f515d 100644 (file)
@@ -106,6 +106,10 @@ public:
    * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::ProjectPoint
    */
   Dali::Vector3 ProjectPoint(Dali::Vector3 origin, Dali::Vector3 direction, float distance) override;
+
+private:
+  Actor mDebugActor;
+  // Physics world owns debug renderer
 };
 
 } // namespace Dali::Toolkit::Physics::Internal
diff --git a/dali-physics/internal/chipmunk-impl/chipmunk-physics-debug-renderer.cpp b/dali-physics/internal/chipmunk-impl/chipmunk-physics-debug-renderer.cpp
new file mode 100644 (file)
index 0000000..2e60d97
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <chipmunk/chipmunk.h>
+#include <dali-physics/internal/chipmunk-impl/chipmunk-physics-adaptor-impl.h>
+#include <dali-physics/internal/chipmunk-impl/chipmunk-physics-debug-renderer.h>
+
+namespace
+{
+GLuint LoadShader(GLenum shaderType, const char* shaderSource)
+{
+  GLuint shader = glCreateShader(shaderType);
+  if(shader != 0)
+  {
+    glShaderSource(shader, 1, &shaderSource, NULL);
+    glCompileShader(shader);
+    GLint compiled = 0;
+    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+    if(compiled != GL_TRUE)
+    {
+      GLint infoLen = 0;
+      glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+
+      if(infoLen > 0)
+      {
+        std::vector<char> logBuffer;
+        logBuffer.resize(infoLen + 1);
+        glGetShaderInfoLog(shader, infoLen, NULL, &logBuffer[0]);
+        fprintf(stderr, "%s\n", &logBuffer[0]);
+        fflush(stderr);
+
+        glDeleteShader(shader);
+        shader = 0;
+      }
+    }
+  }
+  return shader;
+}
+
+GLuint CreateProgram(const char* vertexSource, const char* fragmentSource)
+{
+  GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vertexSource);
+  if(!vertexShader)
+  {
+    return 0;
+  }
+  GLuint fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fragmentSource);
+  if(!fragmentShader)
+  {
+    return 0;
+  }
+  GLuint program = glCreateProgram();
+  if(program)
+  {
+    glAttachShader(program, vertexShader);
+    glAttachShader(program, fragmentShader);
+    glLinkProgram(program);
+    GLint linkStatus = GL_FALSE;
+    glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+    if(linkStatus != GL_TRUE)
+    {
+      GLint bufLength = 0;
+      glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+      if(bufLength)
+      {
+        std::vector<char> logBuffer;
+        logBuffer.resize(bufLength + 1);
+        glGetProgramInfoLog(program, bufLength, NULL, &logBuffer[0]);
+        fprintf(stderr, "%s\n", &logBuffer[0]);
+        fflush(stderr);
+      }
+      glDeleteProgram(program);
+      program = 0;
+    }
+  }
+  return program;
+}
+} // namespace
+
+namespace Dali::Toolkit::Physics::Internal
+{
+static void DebugDrawCircleImpl(cpVect pos, cpFloat angle, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor, cpDataPointer data)
+{
+  auto debugRenderer = static_cast<PhysicsDebugRenderer*>(data);
+  debugRenderer->DrawCircle(pos, angle, radius, outlineColor, fillColor);
+}
+
+static void DebugDrawSegmentImpl(cpVect a, cpVect b, cpSpaceDebugColor color, cpDataPointer data)
+{
+  auto debugRenderer = static_cast<PhysicsDebugRenderer*>(data);
+  debugRenderer->DrawSegment(a, b, color);
+}
+
+void DebugDrawFatSegmentImpl(cpVect a, cpVect b, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor, cpDataPointer data)
+{
+  auto debugRenderer = static_cast<PhysicsDebugRenderer*>(data);
+  debugRenderer->DrawFatSegment(a, b, radius, outlineColor, fillColor);
+}
+
+void DebugDrawPolygonImpl(int count, const cpVect* verts, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor, cpDataPointer data)
+{
+  auto debugRenderer = static_cast<PhysicsDebugRenderer*>(data);
+  debugRenderer->DrawPolygon(count, verts, radius, outlineColor, fillColor);
+}
+
+void DebugDrawDotImpl(cpFloat size, cpVect pos, cpSpaceDebugColor color, cpDataPointer data)
+{
+  auto debugRenderer = static_cast<PhysicsDebugRenderer*>(data);
+  debugRenderer->DrawDot(size, pos, color);
+}
+
+cpSpaceDebugColor DebugDrawColorForShapeImpl(cpShape* shape, cpDataPointer data)
+{
+  auto debugRenderer = static_cast<PhysicsDebugRenderer*>(data);
+  return debugRenderer->DrawColorForShape(shape);
+}
+
+std::unique_ptr<PhysicsDebugRenderer> PhysicsDebugRenderer::New(uint32_t width, uint32_t height, Dali::CameraActor camera, PhysicsAdaptor* adaptor)
+{
+  auto renderer = std::make_unique<PhysicsDebugRenderer>(width, height, camera, adaptor);
+
+  renderer->mRenderCallback = Dali::RenderCallback::New<PhysicsDebugRenderer>(renderer.get(), &PhysicsDebugRenderer::OnRender);
+  return renderer;
+}
+
+PhysicsDebugRenderer::PhysicsDebugRenderer(uint32_t width, uint32_t height, Dali::CameraActor camera, PhysicsAdaptor* adaptor)
+: mCamera(camera),
+  mWidth(width),
+  mHeight(height),
+  mAdaptor(*adaptor),
+  mPositionLocation(-1),
+  mUvsLocation(-1),
+  mRadiusLocation(-1),
+  mFillColourLocation(-1),
+  mOutlineColourLocation(-1),
+  mProjectionLocation(-1),
+  mModelViewLocation(-1),
+  mIndexBufferId(0u),
+  mVertexBufferId(0u),
+  mProgramId(0u)
+{
+  mDebugDrawOptions.drawCircle     = DebugDrawCircleImpl;
+  mDebugDrawOptions.drawSegment    = DebugDrawSegmentImpl;
+  mDebugDrawOptions.drawFatSegment = DebugDrawFatSegmentImpl;
+  mDebugDrawOptions.drawPolygon    = DebugDrawPolygonImpl;
+  mDebugDrawOptions.drawDot        = DebugDrawDotImpl;
+
+  mDebugDrawOptions.flags               = static_cast<cpSpaceDebugDrawFlags>(CP_SPACE_DEBUG_DRAW_SHAPES |
+                                                               CP_SPACE_DEBUG_DRAW_COLLISION_POINTS |
+                                                               CP_SPACE_DEBUG_DRAW_CONSTRAINTS);
+  mDebugDrawOptions.colorForShape       = DebugDrawColorForShapeImpl;
+  mDebugDrawOptions.shapeOutlineColor   = cpSpaceDebugColor{0.0f, 1.0f, 1.0f, 0.9f};
+  mDebugDrawOptions.collisionPointColor = cpSpaceDebugColor{1.0f, 0.0f, 0.0f, 1.0f};
+  mDebugDrawOptions.data                = this;
+}
+
+bool PhysicsDebugRenderer::OnRender(const Dali::RenderCallbackInput& input)
+{
+  if(mState == State::INIT)
+  {
+    Setup();
+    mState = State::RENDER;
+  }
+  glViewport(0, 0, mWidth, mHeight);
+
+  RenderLines(input);
+
+  return false;
+}
+
+// Run on first invocation of callback
+void PhysicsDebugRenderer::Setup()
+{
+  PrepareShader();
+  mPositionLocation      = glGetAttribLocation(mProgramId, "position");
+  mUvsLocation           = glGetAttribLocation(mProgramId, "uvs");
+  mRadiusLocation        = glGetAttribLocation(mProgramId, "radius");
+  mFillColourLocation    = glGetAttribLocation(mProgramId, "fillColor");
+  mOutlineColourLocation = glGetAttribLocation(mProgramId, "outlineColor");
+
+  mProjectionLocation = glGetUniformLocation(mProgramId, "projection");
+  mModelViewLocation  = glGetUniformLocation(mProgramId, "modelView");
+
+  glEnable(GL_DEPTH_TEST);
+  glViewport(0, 0, mWidth, mHeight);
+
+  glGenBuffers(1, &mIndexBufferId);
+  glGenBuffers(1, &mVertexBufferId);
+}
+
+void PhysicsDebugRenderer::UpdateWindowSize(Dali::Vector2 size)
+{
+  mWidth  = size.width;
+  mHeight = size.height;
+}
+
+void PhysicsDebugRenderer::PrepareShader()
+{
+  static const char glVertexShader[] =
+    "#version 300 es\n"
+    "in vec2 position;\n"
+    "in vec2 uvs;\n"
+    "in float radius;\n"
+    "in vec4 fillColor;\n"
+    "in vec4 outlineColor;\n"
+    "out vec2 v_uvs;\n"
+    "out vec4 v_fill;\n"
+    "out vec4 v_outline;\n"
+    "uniform mat4 projection;\n"
+    "uniform mat4 modelView;\n"
+    "void main()\n"
+    "{\n"
+    "    gl_Position = projection * modelView * vec4(position.xy+radius*uvs, 0.0, 1.0);\n"
+    "    v_uvs=uvs;\n"
+    "    v_fill = fillColor;\n"
+    "    v_fill.rgb *= v_fill.a;\n"
+    "    v_outline = outlineColor;\n"
+    "    v_outline.a *= v_outline.a;\n"
+    "}\n";
+
+  static const char glFragmentShader[] =
+    "#version 300 es\n"
+    "precision mediump float;\n"
+    "in vec2 v_uvs;\n"
+    "in vec4 v_fill;\n"
+    "in vec4 v_outline;\n"
+    "out vec4 fragColor;\n"
+    "void main()\n"
+    "{\n"
+    "    float len=length(v_uvs);\n"
+    "    float fw = length(vec2(dFdx(len), dFdy(len)));\n"
+    "    float mask=smoothstep(-1.0, fw-1.0, -len);\n"
+    "    float outline=1.0-fw;\n"
+    "    float outline_mask=smoothstep(outline-fw, outline, len);\n"
+    "    vec4 color = v_fill + (v_outline - v_fill*v_outline.a)*outline_mask;\n"
+    "    fragColor = color*mask;\n"
+    "}\n";
+
+  mProgramId = CreateProgram(glVertexShader, glFragmentShader);
+}
+
+void PhysicsDebugRenderer::RenderLines(const Dali::RenderCallbackInput& input)
+{
+  mModelViewMatrix.SetIdentity();
+  mProjectionMatrix = input.projection;
+
+  Matrix::Multiply(mModelViewMatrix, mModelViewMatrix, input.view);
+  glUseProgram(mProgramId);
+
+  // In theory, input.clippingBox should tell us the actor position in clip-space.
+  // But, it appears to be bugged.
+  glEnable(GL_BLEND);
+  glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBufferId);
+  glBufferData(GL_ELEMENT_ARRAY_BUFFER, mIndices.size() * sizeof(uint16_t), &mIndices[0], GL_STATIC_DRAW);
+  glBindBuffer(GL_ARRAY_BUFFER, mVertexBufferId);
+  glBufferData(GL_ARRAY_BUFFER, mVertices.size() * sizeof(Vertex), &mVertices[0], GL_STATIC_DRAW);
+
+  GLint stride = 52; // 4*(2 + 2 + 1 + 4 + 4) = 4*13=52
+  glVertexAttribPointer(mPositionLocation, 2, GL_FLOAT, GL_FALSE, stride, 0);
+  glEnableVertexAttribArray(mPositionLocation);
+
+  glVertexAttribPointer(mUvsLocation, 2, GL_FLOAT, GL_FALSE, stride, (const void*)8);
+  glEnableVertexAttribArray(mUvsLocation);
+
+  glVertexAttribPointer(mRadiusLocation, 1, GL_FLOAT, GL_FALSE, stride, (const void*)16);
+  glEnableVertexAttribArray(mRadiusLocation);
+
+  glVertexAttribPointer(mFillColourLocation, 4, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<const void*>(20));
+  glEnableVertexAttribArray(mFillColourLocation);
+  glVertexAttribPointer(mOutlineColourLocation, 4, GL_FLOAT, GL_FALSE, stride, reinterpret_cast<const void*>(36));
+  glEnableVertexAttribArray(mOutlineColourLocation);
+
+  glUniformMatrix4fv(mProjectionLocation, 1, GL_FALSE, mProjectionMatrix.AsFloat());
+  glUniformMatrix4fv(mModelViewLocation, 1, GL_FALSE, mModelViewMatrix.AsFloat());
+
+  glDrawElements(GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_SHORT, 0);
+  mIndices.clear();
+  mVertices.clear();
+}
+
+PhysicsDebugRenderer::Vertex* PhysicsDebugRenderer::PushVertices(uint32_t vertexCount, uint32_t indexCount, const uint16_t* indices)
+{
+  auto base = mVertices.size();
+  mVertices.resize(mVertices.size() + vertexCount);
+  mIndices.reserve(mIndices.size() + indexCount);
+  for(uint32_t i = 0; i < indexCount; ++i)
+  {
+    mIndices.push_back(base + indices[i]);
+  }
+
+  return &mVertices[base];
+}
+
+PhysicsDebugRenderer::Vertex PhysicsDebugRenderer::MakeVertex(cpVect pos, float u, float v, float r, Vector4 fill, Vector4 outline)
+{
+  auto daliPos = mAdaptor.TranslateFromPhysicsSpace(Vector3((float)pos.x, (float)pos.y, 0.0f));
+  return Vertex{Vector2(daliPos.x, daliPos.y), Vector2(u, v), r, fill, outline};
+}
+
+void PhysicsDebugRenderer::DrawCircle(cpVect pos, cpFloat angle, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor)
+{
+  float                 r = (float)radius + mPointLineScale;
+  Vector4               fill(fillColor.r, fillColor.g, fillColor.b, fillColor.a);
+  Vector4               outline(outlineColor.r, outlineColor.g, outlineColor.b, outlineColor.a);
+  static const uint16_t indices[] = {0, 1, 2, 0, 2, 3};
+
+  Vertex* vertices = PushVertices(4, 6, indices);
+
+  vertices[0] = MakeVertex(pos, -1, -1, r, fill, outline);
+  vertices[1] = MakeVertex(pos, -1, 1, r, fill, outline);
+  vertices[2] = MakeVertex(pos, 1, 1, r, fill, outline);
+  vertices[3] = MakeVertex(pos, 1, -1, r, fill, outline);
+
+  DrawSegment(pos, cpvadd(pos, cpvmult(cpvforangle(angle), 0.75f * radius)), outlineColor);
+}
+
+void PhysicsDebugRenderer::DrawSegment(cpVect a, cpVect b, cpSpaceDebugColor color)
+{
+  DrawFatSegment(a, b, 0.0f, color, color);
+}
+
+void PhysicsDebugRenderer::DrawFatSegment(cpVect a, cpVect b, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor)
+{
+  static const uint16_t indices[] = {0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5, 4, 5, 6, 5, 6, 7};
+  Vertex*               vertices  = PushVertices(8, 18, indices);
+
+  cpVect t = cpvnormalize(cpvsub(b, a));
+
+  float   r = (float)radius * mPointLineScale;
+  Vector4 fill(fillColor.r, fillColor.g, fillColor.b, fillColor.a);
+  Vector4 outline(outlineColor.r, outlineColor.g, outlineColor.b, outlineColor.a);
+
+  vertices[0] = MakeVertex(a, (-t.x + t.y), (-t.x - t.y), r, fill, outline);
+  vertices[1] = MakeVertex(a, (-t.x - t.y), (+t.x - t.y), r, fill, outline);
+  vertices[2] = MakeVertex(a, (-0.0 + t.y), (-t.x + 0.0), r, fill, outline);
+  vertices[3] = MakeVertex(a, (-0.0 - t.y), (+t.x + 0.0), r, fill, outline);
+  vertices[4] = MakeVertex(a, (+0.0 + t.y), (-t.x - 0.0), r, fill, outline);
+  vertices[5] = MakeVertex(a, (+0.0 - t.y), (+t.x - 0.0), r, fill, outline);
+  vertices[6] = MakeVertex(a, (+t.x + t.y), (-t.x + t.y), r, fill, outline);
+  vertices[7] = MakeVertex(a, (+t.x - t.y), (+t.x + t.y), r, fill, outline);
+}
+
+void PhysicsDebugRenderer::DrawPolygon(int count, const cpVect* verts, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor)
+{
+  Vector4 fill(fillColor.r, fillColor.g, fillColor.b, fillColor.a);
+  Vector4 outline(outlineColor.r, outlineColor.g, outlineColor.b, outlineColor.a);
+
+  std::vector<uint16_t> indices;
+  for(int i = 0; i < count - 2; i++)
+  {
+    indices.push_back(0);
+    indices.push_back(4 * (i + 1));
+    indices.push_back(4 * (i + 2));
+  }
+
+  // Polygon outline triangles.
+  for(int i0 = 0; i0 < count; i0++)
+  {
+    int i1 = (i0 + 1) % count;
+    indices.push_back(4 * i0 + 0);
+    indices.push_back(4 * i0 + 1);
+    indices.push_back(4 * i0 + 2);
+    indices.push_back(4 * i0 + 0);
+    indices.push_back(4 * i0 + 2);
+    indices.push_back(4 * i0 + 3);
+    indices.push_back(4 * i0 + 0);
+    indices.push_back(4 * i0 + 3);
+    indices.push_back(4 * i1 + 0);
+    indices.push_back(4 * i0 + 3);
+    indices.push_back(4 * i1 + 0);
+    indices.push_back(4 * i1 + 1);
+  }
+
+  float inset  = (float)-cpfmax(0, 2 * mPointLineScale - radius);
+  float outset = (float)radius + mPointLineScale;
+  float r      = outset - inset;
+
+  Vertex* vertices = PushVertices(4 * count, 3 * (5 * count - 2), &indices[0]);
+  for(int i = 0; i < count; i++)
+  {
+    cpVect v0     = verts[i];
+    cpVect v_prev = verts[(i + (count - 1)) % count];
+    cpVect v_next = verts[(i + (count + 1)) % count];
+
+    cpVect n1 = cpvnormalize(cpvrperp(cpvsub(v0, v_prev)));
+    cpVect n2 = cpvnormalize(cpvrperp(cpvsub(v_next, v0)));
+    cpVect of = cpvmult(cpvadd(n1, n2), 1.0 / (cpvdot(n1, n2) + 1.0f));
+    cpVect v  = cpvadd(v0, cpvmult(of, inset));
+
+    vertices[4 * i + 0] = MakeVertex(v, 0.0f, 0.0f, 0.0f, fill, outline);
+    vertices[4 * i + 1] = MakeVertex(v, (float)n1.x, (float)n1.y, r, fill, outline);
+    vertices[4 * i + 2] = MakeVertex(v, (float)of.x, (float)of.y, r, fill, outline);
+    vertices[4 * i + 3] = MakeVertex(v, (float)n2.x, (float)n2.y, r, fill, outline);
+  }
+}
+
+void PhysicsDebugRenderer::DrawDot(cpFloat size, cpVect pos, cpSpaceDebugColor color)
+{
+  float                 r = (float)(size * 0.5f * mPointLineScale);
+  Vector4               fill(color.r, color.g, color.b, color.a);
+  static const uint16_t indices[] = {0, 1, 2, 0, 2, 3};
+  Vertex*               vertex    = PushVertices(4, 6, indices);
+  vertex[0]                       = MakeVertex(pos, -1, -1, r, fill, fill);
+  vertex[1]                       = MakeVertex(pos, -1, 1, r, fill, fill);
+  vertex[2]                       = MakeVertex(pos, 1, 1, r, fill, fill);
+  vertex[3]                       = MakeVertex(pos, 1, -1, r, fill, fill);
+}
+
+cpSpaceDebugColor PhysicsDebugRenderer::DrawColorForShape(cpShape* shape)
+{
+  static cpSpaceDebugColor Colors[] = {
+    {0xb5 / 255.0f, 0x89 / 255.0f, 0x00 / 255.0f, 1.0f},
+    {0xcb / 255.0f, 0x4b / 255.0f, 0x16 / 255.0f, 1.0f},
+    {0xdc / 255.0f, 0x32 / 255.0f, 0x2f / 255.0f, 1.0f},
+    {0xd3 / 255.0f, 0x36 / 255.0f, 0x82 / 255.0f, 1.0f},
+    {0x6c / 255.0f, 0x71 / 255.0f, 0xc4 / 255.0f, 1.0f},
+    {0x26 / 255.0f, 0x8b / 255.0f, 0xd2 / 255.0f, 1.0f},
+    {0x2a / 255.0f, 0xa1 / 255.0f, 0x98 / 255.0f, 1.0f},
+    {0x85 / 255.0f, 0x99 / 255.0f, 0x00 / 255.0f, 1.0f},
+  };
+
+  if(cpShapeGetSensor(shape))
+  {
+    return cpSpaceDebugColor{1.0f, 1.0f, 1.0f, 0.1f};
+  }
+  else
+  {
+    cpBody* body = cpShapeGetBody(shape);
+
+    if(cpBodyIsSleeping(body))
+    {
+      return cpSpaceDebugColor{0x58 / 255.0f, 0x6e / 255.0f, 0x75 / 255.0f, 1.0f};
+    }
+    else if(cpBodyIsSleepThresholdExceeded(body, shape))
+    {
+      return cpSpaceDebugColor{0x93 / 255.0f, 0xa1 / 255.0f, 0xa1 / 255.0f, 1.0f};
+    }
+    else
+    {
+      uint32_t val = (uint32_t)cpShapeGetHashId(shape);
+
+      // scramble the bits up using Robert Jenkins' 32 bit integer hash function
+      val = (val + 0x7ed55d16) + (val << 12);
+      val = (val ^ 0xc761c23c) ^ (val >> 19);
+      val = (val + 0x165667b1) + (val << 5);
+      val = (val + 0xd3a2646c) ^ (val << 9);
+      val = (val + 0xfd7046c5) + (val << 3);
+      val = (val ^ 0xb55a4f09) ^ (val >> 16);
+
+      return Colors[val & 0x7];
+    }
+  }
+
+  return cpSpaceDebugColor{1.0f, 1.0f, 1.0f, 1.0f};
+}
+
+} // namespace Dali::Toolkit::Physics::Internal
diff --git a/dali-physics/internal/chipmunk-impl/chipmunk-physics-debug-renderer.h b/dali-physics/internal/chipmunk-impl/chipmunk-physics-debug-renderer.h
new file mode 100644 (file)
index 0000000..2a4335b
--- /dev/null
@@ -0,0 +1,126 @@
+#pragma once
+
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <GLES3/gl3.h>
+#include <chipmunk/chipmunk.h>
+#include <dali/dali.h>
+
+using Dali::Actor;
+using Dali::CameraActor;
+using Dali::Geometry;
+using Dali::Renderer;
+using Dali::Shader;
+using Dali::TextureSet;
+
+namespace Dali::Toolkit::Physics::Internal
+{
+class PhysicsAdaptor;
+
+class PhysicsDebugRenderer
+{
+public:
+  // Creates and initializes a new renderer
+  static std::unique_ptr<PhysicsDebugRenderer> New(uint32_t width, uint32_t height, Dali::CameraActor camera, PhysicsAdaptor* adaptor);
+  /**
+   * Get the callback (for actor creation)
+   */
+
+  std::unique_ptr<Dali::RenderCallback>& GetCallback()
+  {
+    return mRenderCallback;
+  }
+
+  void UpdateWindowSize(Dali::Vector2 size);
+
+  /**
+   * Constructor.
+   * @param[in] width Width of the renderer - viewport
+   * @param[in] height Height of the renderer - viewport
+   */
+  PhysicsDebugRenderer(uint32_t width, uint32_t height, Dali::CameraActor camera, PhysicsAdaptor* adaptor);
+
+  /**
+   * Get the drawing options struct ( construct only )
+   */
+  const cpSpaceDebugDrawOptions& GetDebugDrawOptions()
+  {
+    return mDebugDrawOptions;
+  }
+
+  struct Vertex
+  {
+    Dali::Vector2 position;
+    Dali::Vector2 uvs;
+    float         radius;
+    Dali::Vector4 fillColor;
+    Dali::Vector4 outlineColor;
+  };
+
+public: // Debug functions (Creates indices & verts)
+  void              DrawCircle(cpVect pos, cpFloat angle, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor);
+  void              DrawSegment(cpVect a, cpVect b, cpSpaceDebugColor color);
+  void              DrawFatSegment(cpVect a, cpVect b, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor);
+  void              DrawPolygon(int count, const cpVect* verts, cpFloat radius, cpSpaceDebugColor outlineColor, cpSpaceDebugColor fillColor);
+  void              DrawDot(cpFloat size, cpVect pos, cpSpaceDebugColor color);
+  cpSpaceDebugColor DrawColorForShape(cpShape* shape);
+
+private:
+  bool OnRender(const Dali::RenderCallbackInput& input);
+  void Setup();
+  void PrepareShader();
+  void RenderLines(const Dali::RenderCallbackInput& input);
+
+  Vertex* PushVertices(uint32_t vertexCount, uint32_t indexCount, const uint16_t* indices);
+  Vertex  MakeVertex(cpVect pos, float u, float v, float r, Vector4 fill, Vector4 outline);
+
+private:
+  CameraActor                           mCamera;
+  cpSpaceDebugDrawOptions               mDebugDrawOptions;
+  Renderer                              mDebugRenderer;
+  std::unique_ptr<Dali::RenderCallback> mRenderCallback;
+
+  enum class State
+  {
+    INIT,
+    RENDER
+  } mState{State::INIT};
+
+  std::vector<Vertex>   mVertices;
+  std::vector<uint16_t> mIndices;
+
+  Dali::Matrix    mModelViewMatrix;
+  Dali::Matrix    mViewMatrix;
+  Dali::Matrix    mProjectionMatrix;
+  int             mWidth;
+  int             mHeight;
+  PhysicsAdaptor& mAdaptor;
+
+  float  mPointLineScale{2.0f};
+  GLint  mPositionLocation;
+  GLint  mUvsLocation;
+  GLint  mRadiusLocation;
+  GLint  mFillColourLocation;
+  GLint  mOutlineColourLocation;
+  GLint  mProjectionLocation;
+  GLint  mModelViewLocation;
+  GLuint mIndexBufferId;
+  GLuint mVertexBufferId;
+  GLuint mProgramId;
+};
+
+} // namespace Dali::Toolkit::Physics::Internal
index 6157780..7423edd 100644 (file)
@@ -26,9 +26,6 @@
 
 namespace
 {
-#define GRABBABLE_MASK_BIT (1u << 31)
-cpShapeFilter GRAB_FILTER = {CP_NO_GROUP, GRABBABLE_MASK_BIT, GRABBABLE_MASK_BIT};
-
 inline cpVect ConvertVector(Dali::Vector3 vector)
 {
   return cpv(vector.x, vector.y);
@@ -115,14 +112,23 @@ void ChipmunkPhysicsWorld::Integrate(float timestep)
   {
     cpSpaceStep(mSpace, timestep);
   }
+
+  if(mPhysicsDebugState == Physics::PhysicsAdaptor::DebugState::ON)
+  {
+    if(mDebugRenderer)
+    {
+      cpSpaceDebugDraw(mSpace, const_cast<cpSpaceDebugDrawOptions*>(&mDebugRenderer->GetDebugDrawOptions()));
+    }
+  }
 }
 
-Dali::Any ChipmunkPhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera)
+Dali::Any ChipmunkPhysicsWorld::HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera)
 {
   cpVect           spacePosition = cpv(rayFromWorld.x, rayFromWorld.y);
   cpFloat          radius        = 5.0f;
   cpPointQueryInfo info          = {0};
-  cpShape*         shape         = cpSpacePointQueryNearest(mSpace, spacePosition, radius, GRAB_FILTER, &info);
+  cpShapeFilter    filter        = nativeFilter.Get<cpShapeFilter>();
+  cpShape*         shape         = cpSpacePointQueryNearest(mSpace, spacePosition, radius, filter, &info);
   cpBody*          hitBody{nullptr};
 
   if(shape && cpBodyGetMass(cpShapeGetBody(shape)) < INFINITY)
index fbb2e03..10ba5e8 100644 (file)
@@ -19,6 +19,7 @@
 #include <dali-physics/internal/physics-world-impl.h>
 
 #include <chipmunk/chipmunk.h>
+#include <dali-physics/internal/chipmunk-impl/chipmunk-physics-debug-renderer.h>
 #include <memory>
 
 namespace Dali::Toolkit::Physics::Internal
@@ -37,10 +38,29 @@ public:
 
   void Integrate(float timestep) override;
 
-  Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) override;
+  Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera) override;
+
+  /**
+   * Set the debug renderer. PhysicsWorld will take ownership
+   */
+  void SetDebugRenderer(PhysicsDebugRenderer* renderer)
+  {
+    mDebugRenderer.reset(renderer);
+  }
+
+  PhysicsDebugRenderer& GetDebugRenderer()
+  {
+    return *mDebugRenderer.get();
+  }
+
+  bool HasDebugRenderer()
+  {
+    return mDebugRenderer.get() != nullptr;
+  }
 
 private:
-  cpSpace* mSpace{nullptr};
+  cpSpace*                              mSpace{nullptr};
+  std::unique_ptr<PhysicsDebugRenderer> mDebugRenderer;
 };
 
 } //namespace Dali::Toolkit::Physics::Internal
index 87c7cb2..19137dd 100644 (file)
@@ -5,6 +5,7 @@ set(physics3d_internal_dir ${physics_internal_dir}/bullet-impl)
 set(physics2d_src_files ${physics_src_files}
   ${physics2d_internal_dir}/chipmunk-physics-actor-impl.cpp
   ${physics2d_internal_dir}/chipmunk-physics-adaptor-impl.cpp
+  ${physics2d_internal_dir}/chipmunk-physics-debug-renderer.cpp
   ${physics2d_internal_dir}/chipmunk-physics-world-impl.cpp
   ${physics_internal_dir}/physics-adaptor-impl.cpp
   ${physics_internal_dir}/physics-world-impl.cpp
index cd43633..b0ca04d 100644 (file)
@@ -96,11 +96,11 @@ bool PhysicsWorld::OnUpdate(Dali::UpdateProxy& updateProxy, float elapsedSeconds
   if(mNotifySyncPoint != Dali::UpdateProxy::INVALID_SYNC &&
      mNotifySyncPoint == updateProxy.PopSyncPoint())
   {
-    do
+    while(!commandQueue.empty())
     {
       commandQueue.front()(); // Execute the queued methods
       commandQueue.pop();
-    } while(!commandQueue.empty());
+    }
 
     mNotifySyncPoint = Dali::UpdateProxy::INVALID_SYNC;
   }
index d6e1097..b1c9460 100644 (file)
@@ -111,11 +111,12 @@ public:
    *
    * @param[in] rayFromWorld The origin in physics world space
    * @param[in] rayToWorld A point along the direction on the far side of the physics world
+   * @param[in] nativeFilter a native body / shape filter
    * @param[out] localPivot The hit point local to the body
    * @param[out] distanceFromCamera The distance of the pick point from the camera
    * @return Empty value if no dynamic body found, otherwise a valid ptr to the hit body.
    */
-  virtual Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera) = 0;
+  virtual Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera) = 0;
 
   /**
    * @copydoc Dali::Toolkit::Physics::PhysicsAdaptor::SetIntegrationState
index 41c7da7..0bdd0c0 100644 (file)
@@ -98,11 +98,12 @@ public:
      * @SINCE_2_2.43
      * @param[in] rayFromWorld The origin in physics world space
      * @param[in] rayToWorld A point along the direction on the far side of the physics world
+     * @param[in] nativeFilter a native body / shape filter
      * @param[out] localPivot The hit point local to the body
      * @param[out] distanceFromCamera The distance of the pick point from the camera
      * @return Empty value if no dynamic body found, otherwise a valid ptr to the hit body.
      */
-    Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera);
+    Dali::Any HitTest(Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera);
 
     // Not copyable
     ScopedPhysicsAccessor(ScopedPhysicsAccessor&) = delete;
@@ -418,7 +419,8 @@ public:
    *     btVector3 rayFromWorld, rayToWorld;
    *     physicsAdaptor.BuildPickingRay(origin, direction, rayFromWorld, rayToWorld);
    *     auto scopedAccessor = physicsAdaptor.GetPhysicsAccessor();
-   *     body = scopedAccessor->Get().HitTest(rayFromWorld, rayToWorld, ..);
+   *     Dali::Any nativeFilter;
+   *     body = scopedAccessor->Get().HitTest(rayFromWorld, rayToWorld, nativeFilter, ..);
    *   }
    */
   void BuildPickingRay(Dali::Vector3 origin, Dali::Vector3 direction, Dali::Vector3& rayFromWorld, Dali::Vector3& rayToWorld);
index 1f4b6e8..1fad04c 100644 (file)
@@ -52,9 +52,9 @@ Dali::Any PhysicsAdaptor::ScopedPhysicsAccessor::GetNative()
 }
 
 Dali::Any PhysicsAdaptor::ScopedPhysicsAccessor::HitTest(
-  Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Vector3& localPivot, float& distanceFromCamera)
+  Dali::Vector3 rayFromWorld, Dali::Vector3 rayToWorld, Dali::Any nativeFilter, Dali::Vector3& localPivot, float& distanceFromCamera)
 {
-  return mImpl->mPhysicsWorld.HitTest(rayFromWorld, rayToWorld, localPivot, distanceFromCamera);
+  return mImpl->mPhysicsWorld.HitTest(rayFromWorld, rayToWorld, nativeFilter, localPivot, distanceFromCamera);
 }
 
 } // namespace Dali::Toolkit::Physics
index 7e6943d..8e46cc3 100644 (file)
@@ -76,6 +76,9 @@ CP_EXPORT void cpBodySleepWithGroup(cpBody *body, cpBody *group);
 /// Returns true if the body is sleeping.
 CP_EXPORT cpBool cpBodyIsSleeping(const cpBody *body);
 
+// Returns true if the body is exceeding the sleep threshold
+CP_EXPORT cpBool cpBodyIsSleepThresholdExceeded(const cpBody *body, const cpShape *shape);
+
 /// Get the type of the body.
 CP_EXPORT cpBodyType cpBodyGetType(cpBody *body);
 /// Set the type of the body.
index c78ed05..2b04062 100644 (file)
@@ -79,6 +79,9 @@ CP_EXPORT void cpShapeDestroy(cpShape *shape);
 /// Destroy and Free a shape.
 CP_EXPORT void cpShapeFree(cpShape *shape);
 
+/// Get the hash ID of the shape
+CP_EXPORT cpHashValue cpShapeGetHashId(cpShape* shape);
+
 /// Update, cache and return the bounding box of a shape based on the body it's attached to.
 CP_EXPORT cpBB cpShapeCacheBB(cpShape *shape);
 /// Update, cache and return the bounding box of a shape with an explicit transformation.
index 34b30eb..55f7954 100644 (file)
@@ -39,6 +39,12 @@ if(ANDROID)
   FIND_LIBRARY(LOGLIB log)
 endif(ANDROID)
 
+# If you want to reduce the size of the library slightly, uncomment this section
+#
+#if(NOT ENABLE_DEBUG)
+#  add_definitions( "-DCP_SPACE_DISABLE_DEBUG_API")
+#endif()
+
 if(BUILD_SHARED)
   add_library(chipmunk SHARED
     ${chipmunk_source_files}
@@ -117,4 +123,3 @@ if (ENABLE_PKG_CONFIGURE)
         DESTINATION ${LIB_DIR}/pkgconfig
     )
 endif()
-
index 8ad2bc9..e5caaf9 100644 (file)
@@ -133,6 +133,12 @@ cpBodyIsSleeping(const cpBody *body)
        return (body->sleeping.root != ((cpBody*)0));
 }
 
+cpBool
+cpBodyIsSleepThresholdExceeded(const cpBody *body, const cpShape *shape)
+{
+  return body->sleeping.idleTime > shape->space->sleepTimeThreshold;
+}
+
 cpBodyType
 cpBodyGetType(cpBody *body)
 {
index 513b535..942bfff 100644 (file)
@@ -109,6 +109,12 @@ cpFloat cpShapeGetMoment(cpShape *shape){ return shape->massInfo.m*shape->massIn
 cpFloat cpShapeGetArea(cpShape *shape){ return shape->massInfo.area; }
 cpVect cpShapeGetCenterOfGravity(cpShape *shape) { return shape->massInfo.cog; }
 
+cpHashValue
+cpShapeGetHashId(cpShape* shape)
+{
+  return shape->hashid;
+}
+
 cpBB
 cpShapeGetBB(const cpShape *shape)
 {
index 7e46322..faa354c 100644 (file)
@@ -29,7 +29,7 @@ namespace Toolkit
 {
 const unsigned int TOOLKIT_MAJOR_VERSION = 2;
 const unsigned int TOOLKIT_MINOR_VERSION = 2;
-const unsigned int TOOLKIT_MICRO_VERSION = 42;
+const unsigned int TOOLKIT_MICRO_VERSION = 43;
 const char* const  TOOLKIT_BUILD_DATE    = __DATE__ " " __TIME__;
 
 #ifdef DEBUG_ENABLED
index 48fab3d..da90ed7 100644 (file)
@@ -1,6 +1,6 @@
 Name:       dali2-toolkit
 Summary:    Dali 3D engine Toolkit
-Version:    2.2.42
+Version:    2.2.43
 Release:    1
 Group:      System/Libraries
 License:    Apache-2.0 and BSD-3-Clause and MIT