Browse Source

Physics: Some work on the player controller

Panagiotis Christopoulos Charitos 9 years ago
parent
commit
daf94abd38

+ 38 - 69
CMakeLists.txt

@@ -39,6 +39,16 @@ else()
 	set(GCC FALSE)
 	set(GCC FALSE)
 endif()
 endif()
 
 
+################################################################################
+# Some functions                                                               #
+################################################################################
+
+macro(defineStaticExternalLibrary extProj extLib extLibFname)
+	add_library(${extLib} STATIC IMPORTED GLOBAL)
+	set_property(TARGET ${extLib} PROPERTY IMPORTED_LOCATION ${extLibFname})
+	add_dependencies(${extLib} ${extProj})
+endmacro()
+
 ################################################################################
 ################################################################################
 # Configuration                                                                #
 # Configuration                                                                #
 ################################################################################
 ################################################################################
@@ -54,8 +64,6 @@ option(ANKI_BUILD_SANDBOX "Build sandbox application" ON)
 option(ANKI_BUILD_BENCH "Build benchmark application" OFF)
 option(ANKI_BUILD_BENCH "Build benchmark application" OFF)
 option(ANKI_BUILD_SAMPLES "Build sample applications" ON)
 option(ANKI_BUILD_SAMPLES "Build sample applications" ON)
 
 
-option(ANKI_WITH_GPERFTOOLS_PROF "Link with gperftools profiler" OFF)
-
 option(ANKI_STRIP "Srip the symbols from the executables" OFF)
 option(ANKI_STRIP "Srip the symbols from the executables" OFF)
 
 
 option(ANKI_ENABLE_TRACE "Enable performance tracing. Small overhead" OFF)
 option(ANKI_ENABLE_TRACE "Enable performance tracing. Small overhead" OFF)
@@ -237,9 +245,7 @@ if(SDL)
 	ExternalProject_Get_Property(SDL2_PROJECT install_dir)
 	ExternalProject_Get_Property(SDL2_PROJECT install_dir)
 	set(SDL2_INSTALL_DIR ${install_dir})
 	set(SDL2_INSTALL_DIR ${install_dir})
 
 
-	add_library(SDL2_LIB STATIC IMPORTED)
-	set_property(TARGET SDL2_LIB PROPERTY IMPORTED_LOCATION ${SDL2_INSTALL_DIR}/lib/libSDL2.a)
-	add_dependencies(SDL2_LIB SDL2_PROJECT)
+	defineStaticExternalLibrary(SDL2_PROJECT SDL2_LIB "${SDL2_INSTALL_DIR}/lib/libSDL2${CMAKE_STATIC_LIBRARY_SUFFIX}")
 else()
 else()
 	set(SDL2_INSTALL_DIR "")
 	set(SDL2_INSTALL_DIR "")
 endif()
 endif()
@@ -253,10 +259,10 @@ ExternalProject_Add(
 	CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/newton_build -DCMAKE_BUILD_TYPE=Release 
 	CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/newton_build -DCMAKE_BUILD_TYPE=Release 
 	-DNEWTON_DEMOS_SANDBOX=OFF -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})
 	-DNEWTON_DEMOS_SANDBOX=OFF -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER})
 
 
-add_library(NEWTON_LIB SHARED IMPORTED)
-set_property(TARGET NEWTON_LIB PROPERTY IMPORTED_LOCATION 
-	"${CMAKE_CURRENT_BINARY_DIR}/newton_build/lib/libNewton${CMAKE_SHARED_LIBRARY_SUFFIX}")
-add_dependencies(NEWTON_LIB NEWTON_PROJECT)
+defineStaticExternalLibrary(NEWTON_PROJECT NEWTON_LIB "${CMAKE_CURRENT_BINARY_DIR}/newton_build/src/NEWTON_PROJECT-build/lib/libNewton${CMAKE_STATIC_LIBRARY_SUFFIX}")
+defineStaticExternalLibrary(NEWTON_PROJECT NEWTON_JOINTS_LIB "${CMAKE_CURRENT_BINARY_DIR}/newton_build/src/NEWTON_PROJECT-build/lib/libdCustomJoints${CMAKE_STATIC_LIBRARY_SUFFIX}")
+defineStaticExternalLibrary(NEWTON_PROJECT NEWTON_CONTAINERS_LIB "${CMAKE_CURRENT_BINARY_DIR}/newton_build/src/NEWTON_PROJECT-build/lib/libdContainers${CMAKE_STATIC_LIBRARY_SUFFIX}")
+defineStaticExternalLibrary(NEWTON_PROJECT NEWTON_MATH_LIB "${CMAKE_CURRENT_BINARY_DIR}/newton_build/src/NEWTON_PROJECT-build/lib/libdMath${CMAKE_STATIC_LIBRARY_SUFFIX}")
 
 
 # freetype
 # freetype
 ExternalProject_Add(
 ExternalProject_Add(
@@ -268,9 +274,7 @@ ExternalProject_Add(
 
 
 ExternalProject_Get_Property(FREETYPE_PROJECT install_dir)
 ExternalProject_Get_Property(FREETYPE_PROJECT install_dir)
 set(FREETYPE_INSTALL_DIR ${install_dir})
 set(FREETYPE_INSTALL_DIR ${install_dir})
-add_library(FREETYPE_LIB STATIC IMPORTED)
-set_property(TARGET FREETYPE_LIB PROPERTY IMPORTED_LOCATION ${FREETYPE_INSTALL_DIR}/lib/libfreetype.a)
-add_dependencies(FREETYPE_LIB FREETYPE_PROJECT)
+defineStaticExternalLibrary(FREETYPE_PROJECT FREETYPE_LIB "${FREETYPE_INSTALL_DIR}/lib/libfreetype${CMAKE_STATIC_LIBRARY_SUFFIX}")
 
 
 # glslang
 # glslang
 if(VULKAN)
 if(VULKAN)
@@ -284,25 +288,11 @@ if(VULKAN)
 	ExternalProject_Get_Property(GLSLANG_PROJECT install_dir)
 	ExternalProject_Get_Property(GLSLANG_PROJECT install_dir)
 	set(GLSLANG_INSTALL_DIR ${install_dir})
 	set(GLSLANG_INSTALL_DIR ${install_dir})
 
 
-	add_library(GLSLANG_LIB STATIC IMPORTED)
-	set_property(TARGET GLSLANG_LIB PROPERTY IMPORTED_LOCATION ${GLSLANG_INSTALL_DIR}/lib/libglslang.a)
-	add_dependencies(GLSLANG_LIB GLSLANG_PROJECT)
-
-	add_library(SPIRV_LIB STATIC IMPORTED)
-	set_property(TARGET SPIRV_LIB PROPERTY IMPORTED_LOCATION ${GLSLANG_INSTALL_DIR}/lib/libSPIRV.a)
-	add_dependencies(SPIRV_LIB GLSLANG_PROJECT)
-
-	add_library(OSD_LIB STATIC IMPORTED)
-	set_property(TARGET OSD_LIB PROPERTY IMPORTED_LOCATION ${GLSLANG_INSTALL_DIR}/lib/libOSDependent.a)
-	add_dependencies(OSD_LIB GLSLANG_PROJECT)
-
-	add_library(GLC_LIB STATIC IMPORTED)
-	set_property(TARGET GLC_LIB PROPERTY IMPORTED_LOCATION ${GLSLANG_INSTALL_DIR}/lib/libOGLCompiler.a)
-	add_dependencies(GLC_LIB GLSLANG_PROJECT)
-
-	add_library(HLSL_LIB STATIC IMPORTED)
-	set_property(TARGET HLSL_LIB PROPERTY IMPORTED_LOCATION ${GLSLANG_INSTALL_DIR}/lib/libHLSL.a)
-	add_dependencies(HLSL_LIB GLSLANG_PROJECT)
+	defineStaticExternalLibrary(GLSLANG_PROJECT GLSLANG_LIB "${GLSLANG_INSTALL_DIR}/lib/libglslang${CMAKE_STATIC_LIBRARY_SUFFIX}")
+	defineStaticExternalLibrary(GLSLANG_PROJECT SPIRV_LIB "${GLSLANG_INSTALL_DIR}/lib/libSPIRV${CMAKE_STATIC_LIBRARY_SUFFIX}")
+	defineStaticExternalLibrary(GLSLANG_PROJECT OSD_LIB "${GLSLANG_INSTALL_DIR}/lib/libOSDependent${CMAKE_STATIC_LIBRARY_SUFFIX}")
+	defineStaticExternalLibrary(GLSLANG_PROJECT GLC_LIB "${GLSLANG_INSTALL_DIR}/lib/libOGLCompiler${CMAKE_STATIC_LIBRARY_SUFFIX}")
+	defineStaticExternalLibrary(GLSLANG_PROJECT HLSL_LIB "${GLSLANG_INSTALL_DIR}/lib/libHLSL${CMAKE_STATIC_LIBRARY_SUFFIX}")
 endif()
 endif()
 
 
 foreach(TMP ${ANKI_EXTERN_SUB_DIRS})
 foreach(TMP ${ANKI_EXTERN_SUB_DIRS})
@@ -352,14 +342,24 @@ else()
 	set(ANKI_DEBUG 0)
 	set(ANKI_DEBUG 0)
 endif()
 endif()
 
 
-CONFIGURE_FILE("src/anki/Config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/anki/Config.h")
-INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/anki/Config.h" DESTINATION "${INCLUDE_INSTALL_DIR}/anki")
+configure_file("src/anki/Config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/anki/Config.h")
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/anki/Config.h" DESTINATION "${INCLUDE_INSTALL_DIR}/anki")
 
 
 # Include & lib directories
 # Include & lib directories
-include_directories("src" "thirdparty/tinyxml2/include" "thirdparty/lua" "thirdparty/z" 
-	"${SDL2_INSTALL_DIR}/include/SDL2/" "${FREETYPE_INSTALL_DIR}/include/freetype2/" 
-	"thirdparty/newton/coreLibrary_300/source/" "${CMAKE_CURRENT_BINARY_DIR}" 
-	${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glslang thirdparty)
+include_directories("src" 
+	"thirdparty/tinyxml2/include" 
+	"thirdparty/lua" 
+	"thirdparty/z" 
+	"${SDL2_INSTALL_DIR}/include/SDL2/" 
+	"${FREETYPE_INSTALL_DIR}/include/freetype2/" 
+	"thirdparty/newton/coreLibrary_300/source/newton" 
+	"thirdparty/newton/packages/dCustomJoints"
+	"thirdparty/newton/packages/dContainers" 
+	"thirdparty/newton/packages/dMath" 
+	"thirdparty/newton/packages/thirdParty/timeTracker/"
+	"${CMAKE_CURRENT_BINARY_DIR}" 
+	"${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/glslang" 
+	"thirdparty")
 
 
 if(LINUX OR MACOS OR WINDOWS)
 if(LINUX OR MACOS OR WINDOWS)
 	include_directories("thirdparty/GLEW/include")
 	include_directories("thirdparty/GLEW/include")
@@ -427,15 +427,7 @@ endforeach()
 
 
 add_library(anki src/anki/Dummy.cpp "${_SYS_SRC}")
 add_library(anki src/anki/Dummy.cpp "${_SYS_SRC}")
 
 
-target_link_libraries(anki ${ANKI_LIBS} ankitinyxml2 ankilua ankiz NEWTON_LIB ${ANKI_GPERFTOOLS_LIBS} SDL2_LIB FREETYPE_LIB ${_SYS})
-
-if(VULKAN)
-#target_link_libraries(anki GLSLANG_LIB)
-endif()
-
-if(SDL)
-	target_link_libraries(anki SDL2_LIB)
-endif()
+target_link_libraries(anki ${ANKI_LIBS} ankitinyxml2 ankilua ankiz FREETYPE_LIB ${_SYS})
 
 
 ################################################################################
 ################################################################################
 # AnKi extra                                                                   #
 # AnKi extra                                                                   #
@@ -460,26 +452,3 @@ endif()
 if(ANKI_BUILD_BENCH)
 if(ANKI_BUILD_BENCH)
 	add_subdirectory(bench)
 	add_subdirectory(bench)
 endif()
 endif()
-
-################################################################################
-# Android                                                                      #
-################################################################################
-if(${ANDROID})
-	# 1. generate Android.mk
-	FILE(WRITE ./jni/Android.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n")
-
-	# 2. generate gdb.setup
-	GET_DIRECTORY_PROPERTY(include_directories DIRECTORY . include_directories)
-	STRING(REGEX REPLACE ";" " " include_directories "${include_directories}")
-	FILE(WRITE ./libs/${ANDROID_NDK_ABI_NAME}/gdb.setup "set solib-search-path ./libs/${ANDROID_NDK_ABI_NAME}\n")
-	FILE(APPEND ./libs/${ANDROID_NDK_ABI_NAME}/gdb.setup "directory ${include_directories} ${CMAKE_CURRENT_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}\n")
-
-	# 3. copy gdbserver executable
-	FILE(COPY ${ANDROID_NDK}/prebuilt/android-arm/gdbserver/gdbserver DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/libs/${ANDROID_NDK_ABI_NAME}/)
-
-	set(LIBRARY_NAME ankibench)
-
-	# 4. copy lib to obj
-	#ADD_CUSTOM_COMMAND(TARGET ${LIBRARY_NAME} POST_BUILD COMMAND mkdir -p ./obj/local/${ANDROID_NDK_ABI_NAME}/)
-	#ADD_CUSTOM_COMMAND(TARGET ${LIBRARY_NAME} POST_BUILD COMMAND cp ./libs/${ANDROID_NDK_ABI_NAME}/lib${LIBRARY_NAME}.so ./obj/local/${ANDROID_NDK_ABI_NAME}/)
-endif()

+ 1 - 1
sandbox/Main.cpp

@@ -10,7 +10,7 @@
 
 
 using namespace anki;
 using namespace anki;
 
 
-#define PLAYER 0
+#define PLAYER 1
 #define MOUSE 1
 #define MOUSE 1
 
 
 class MyApp : public App
 class MyApp : public App

+ 1 - 1
src/anki/physics/CMakeLists.txt

@@ -2,5 +2,5 @@ file(GLOB ANKI_PHYS_SOURCES *.cpp)
 file(GLOB ANKI_PHYS_HEADERS *.h)
 file(GLOB ANKI_PHYS_HEADERS *.h)
 
 
 add_library(ankiphysics ${ANKI_PHYS_SOURCES} ${ANKI_PHYS_HEADERS})
 add_library(ankiphysics ${ANKI_PHYS_SOURCES} ${ANKI_PHYS_HEADERS})
-target_link_libraries(ankiphysics NEWTON_LIB)
+target_link_libraries(ankiphysics NEWTON_LIB NEWTON_JOINTS_LIB NEWTON_CONTAINERS_LIB NEWTON_MATH_LIB)
 
 

+ 14 - 13
src/anki/physics/Common.h

@@ -9,7 +9,10 @@
 #include <anki/util/Enum.h>
 #include <anki/util/Enum.h>
 #include <anki/util/Ptr.h>
 #include <anki/util/Ptr.h>
 #include <anki/Math.h>
 #include <anki/Math.h>
-#include <newton/Newton.h>
+
+// Common newton libs
+#include <Newton.h>
+#include <dLinearAlgebra.h>
 
 
 namespace anki
 namespace anki
 {
 {
@@ -51,28 +54,26 @@ enum class PhysicsMaterialBit : U16
 };
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(PhysicsMaterialBit, inline)
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(PhysicsMaterialBit, inline)
 
 
-/// Convert newton to AnKi.
-ANKI_USE_RESULT inline Quat toAnki(const Quat& q)
+ANKI_USE_RESULT inline Vec4 toAnki(const dVector& v)
 {
 {
-	return Quat(q.y(), q.z(), q.w(), q.x());
+	return Vec4(v.m_x, v.m_y, v.m_z, v.m_w);
 }
 }
 
 
-/// Convert AnKi to Newton.
-ANKI_USE_RESULT inline Quat toNewton(const Quat& q)
+ANKI_USE_RESULT inline dVector toNewton(const Vec4& v)
 {
 {
-	return Quat(q.w(), q.x(), q.y(), q.z());
+	return dVector(v.x(), v.y(), v.z(), v.w());
 }
 }
 
 
-/// Convert newton to AnKi.
-ANKI_USE_RESULT inline Mat4 toAnki(const Mat4& m)
+ANKI_USE_RESULT inline Mat4 toAnki(const dMatrix& m)
 {
 {
-	return m.getTransposed();
+	Mat4 ak(*reinterpret_cast<const Mat4*>(&m));
+	return ak.getTransposed();
 }
 }
 
 
-/// Convert AnKi to Newton.
-ANKI_USE_RESULT inline Mat4 toNewton(const Mat4& m)
+ANKI_USE_RESULT inline dMatrix toNewton(const Mat4& m)
 {
 {
-	return m.getTransposed();
+	Mat4 transp = m.getTransposed();
+	return dMatrix(&transp(0, 0));
 }
 }
 /// @}
 /// @}
 
 

+ 3 - 3
src/anki/physics/PhysicsBody.cpp

@@ -34,7 +34,7 @@ PhysicsBody::~PhysicsBody()
 Error PhysicsBody::create(const PhysicsBodyInitInfo& init)
 Error PhysicsBody::create(const PhysicsBodyInitInfo& init)
 {
 {
 	// Create
 	// Create
-	Mat4 trf = toNewton(Mat4(init.m_startTrf));
+	dMatrix trf = toNewton(Mat4(init.m_startTrf));
 
 
 	if(init.m_static)
 	if(init.m_static)
 	{
 	{
@@ -45,7 +45,7 @@ Error PhysicsBody::create(const PhysicsBodyInitInfo& init)
 		m_sceneCollisionProxy = NewtonSceneCollisionAddSubCollision(scene, init.m_shape->getNewtonShape());
 		m_sceneCollisionProxy = NewtonSceneCollisionAddSubCollision(scene, init.m_shape->getNewtonShape());
 		NewtonSceneCollisionEndAddRemove(scene);
 		NewtonSceneCollisionEndAddRemove(scene);
 
 
-		NewtonSceneCollisionSetSubCollisionMatrix(scene, m_sceneCollisionProxy, &trf[0]);
+		NewtonSceneCollisionSetSubCollisionMatrix(scene, m_sceneCollisionProxy, &trf[0][0]);
 
 
 		return ErrorCode::NONE;
 		return ErrorCode::NONE;
 	}
 	}
@@ -55,7 +55,7 @@ Error PhysicsBody::create(const PhysicsBodyInitInfo& init)
 	}
 	}
 	else
 	else
 	{
 	{
-		m_body = NewtonCreateDynamicBody(m_world->getNewtonWorld(), init.m_shape->getNewtonShape(), &trf(0, 0));
+		m_body = NewtonCreateDynamicBody(m_world->getNewtonWorld(), init.m_shape->getNewtonShape(), &trf[0][0]);
 	}
 	}
 
 
 	if(!m_body)
 	if(!m_body)

+ 34 - 626
src/anki/physics/PhysicsPlayerController.cpp

@@ -9,660 +9,68 @@
 namespace anki
 namespace anki
 {
 {
 
 
-class CustomControllerConvexRayFilter
+CharacterControllerManager::CharacterControllerManager(PhysicsWorld* world)
+	: CustomPlayerControllerManager(world->getNewtonWorld())
+	, m_world(world)
 {
 {
-public:
-	const NewtonBody* m_me = nullptr;
-	Vec4 m_hitContact = Vec4(0.0);
-	Vec4 m_hitNormal = Vec4(0.0);
-	const NewtonBody* m_hitBody = nullptr;
-	const NewtonCollision* m_shapeHit = nullptr;
-	U32 m_collisionId = 0;
-	F32 m_intersectParam = 1.2;
-
-	static F32 filterCallback(const NewtonBody* const body,
-		const NewtonCollision* const shapeHit,
-		const dFloat* const hitContact,
-		const dFloat* const hitNormal,
-		dLong collisionId,
-		void* const userData,
-		dFloat intersectParam)
-	{
-		CustomControllerConvexRayFilter* filter = static_cast<CustomControllerConvexRayFilter*>(userData);
-
-		ANKI_ASSERT(body != filter->m_me);
-
-		if(intersectParam < filter->m_intersectParam)
-		{
-			filter->m_hitBody = body;
-			filter->m_shapeHit = shapeHit;
-			filter->m_collisionId = collisionId;
-			filter->m_intersectParam = intersectParam;
-			filter->m_hitContact = Vec4(hitContact[0], hitContact[1], hitContact[2], 0.0);
-			filter->m_hitNormal = Vec4(hitNormal[0], hitNormal[1], hitNormal[2], 0.0);
-		}
-
-		return intersectParam;
-	}
-
-	static unsigned prefilterCallback(
-		const NewtonBody* const body, const NewtonCollision* const myCollision, void* const userData)
-	{
-		CustomControllerConvexRayFilter* filter = static_cast<CustomControllerConvexRayFilter*>(userData);
-
-		return (body != filter->m_me) ? 1 : 0;
-	}
-};
-
-struct CustomControllerConvexCastPreFilter
-{
-	const NewtonBody* m_me = nullptr;
-
-	CustomControllerConvexCastPreFilter(NewtonBody* body)
-		: m_me(body)
-	{
-		ANKI_ASSERT(m_me != nullptr);
-	}
-
-	static unsigned prefilterCallback(
-		const NewtonBody* const body, const NewtonCollision* const myCollision, void* const userData)
-	{
-		CustomControllerConvexCastPreFilter* filter = static_cast<CustomControllerConvexCastPreFilter*>(userData);
-
-		return (body != filter->m_me) ? 1 : 0;
-	}
-};
+}
 
 
-static Vec4 calcAverageOmega(Quat q0, const Quat& q1, F32 invdt)
+void CharacterControllerManager::ApplyPlayerMove(CustomPlayerController* const controller, dFloat timestep)
 {
 {
-	if(q0.dot(q1) < 0.0)
-	{
-		q0 *= -1.0f;
-	}
+	ANKI_ASSERT(controller);
 
 
-	Quat dq(q0.getConjugated().combineRotations(q1));
-	Vec4 omegaDir(dq.x(), dq.y(), dq.z(), 0.0);
+	NewtonBody* body = controller->GetBody();
+	PhysicsPlayerController* player = static_cast<PhysicsPlayerController*>(NewtonBodyGetUserData(body));
+	ANKI_ASSERT(player);
 
 
-	F32 dirMag2 = omegaDir.getLengthSquared();
-	if(dirMag2 < 1.0e-5 * 1.0e-5)
-	{
-		return Vec4(0.0);
-	}
-
-	F32 dirMagInv = 1.0 / sqrt(dirMag2);
-	F32 dirMag = dirMag2 * dirMagInv;
+	dVector gravity = toNewton(player->getWorld().getGravity());
+	F32 angle = acos(Vec4(0.0, 0.0, -1.0, 0.0).dot(player->m_forwardDir));
 
 
-	F32 omegaMag = 2.0 * atan2(dirMag, dq.w()) * invdt;
-	return omegaDir * (dirMagInv * omegaMag);
+	controller->SetPlayerVelocity(
+		player->m_forwardSpeed, player->m_strafeSpeed, player->m_jumpSpeed, angle, gravity, timestep);
 }
 }
 
 
-static Quat integrateOmega(const Quat& rot, const Vec4& omega, F32 dt)
+PhysicsPlayerController::~PhysicsPlayerController()
 {
 {
-	ANKI_ASSERT(omega.w() == 0.0);
-	Quat rotation(rot);
-	F32 omegaMag2 = omega.dot(omega);
-	F32 errAngle2 = toRad(0.0125) * toRad(0.0125);
-	if(omegaMag2 > errAngle2)
+	if(m_newtonPlayer)
 	{
 	{
-		F32 invOmegaMag = 1.0 / sqrt(omegaMag2);
-		Vec4 omegaAxis(omega * invOmegaMag);
-		F32 omegaAngle = invOmegaMag * omegaMag2 * dt;
-		Quat deltaRotation(Axisang(omegaAngle, omegaAxis.xyz()));
-		rotation = rotation.combineRotations(deltaRotation);
-		rotation = rotation * (1.0 / sqrt(rotation.dot(rotation)));
+		getWorld().getCharacterControllerManager().DestroyController(m_newtonPlayer);
 	}
 	}
-
-	return rotation;
-}
-
-PhysicsPlayerController::~PhysicsPlayerController()
-{
-	NewtonDestroyCollision(m_upperBodyShape);
-	NewtonDestroyCollision(m_supportShape);
-	NewtonDestroyCollision(m_castingShape);
-	NewtonDestroyBody(m_body);
 }
 }
 
 
 Error PhysicsPlayerController::create(const PhysicsPlayerControllerInitInfo& init)
 Error PhysicsPlayerController::create(const PhysicsPlayerControllerInitInfo& init)
 {
 {
-	NewtonWorld* world = m_world->getNewtonWorld();
-
-	m_restrainingDistance = MIN_RESTRAINING_DISTANCE;
-	m_innerRadius = init.m_innerRadius;
-	m_outerRadius = init.m_outerRadius;
-	m_height = init.m_height;
-	m_stepHeight = init.m_stepHeight;
-	m_isJumping = false;
-
-	m_gravity = m_world->getGravity();
+	dMatrix playerAxis;
+	playerAxis[0] = dVector(0.0f, 1.0f, 0.0f, 0.0f); // the y axis is the character up vector
+	playerAxis[1] = dVector(0.0f, 0.0f, -1.0f, 0.0f); // the x axis is the character front direction
+	playerAxis[2] = playerAxis[0].CrossProduct(playerAxis[1]);
+	playerAxis[3] = dVector(0.0f, 0.0f, 0.0f, 1.0f);
 
 
-	setClimbSlope(toRad(45.0));
+	m_newtonPlayer = getWorld().getCharacterControllerManager().CreatePlayer(
+		init.m_mass, init.m_outerRadius, init.m_innerRadius, init.m_height, init.m_stepHeight, playerAxis);
 
 
-	Mat4 localAxis(Mat4::getIdentity());
-
-	m_upDir = localAxis.getColumn(1);
-	m_frontDir = localAxis.getColumn(2);
-
-	m_groundPlane = Vec4(0.0);
-	m_groundVelocity = Vec4(0.0);
-
-	const U steps = 12;
-	Array2d<Vec4, 2, steps> convexPoints;
-
-	// Create an inner thin cylinder
-	F32 shapeHeight = m_height;
-	ANKI_ASSERT(shapeHeight > 0.0);
-	Vec4 p0(m_innerRadius, 0.0, 0.0, 0.0);
-	Vec4 p1(m_innerRadius, shapeHeight, 0.0, 0.0);
-
-	for(U i = 0; i < steps; ++i)
+	if(m_newtonPlayer == nullptr)
 	{
 	{
-		Mat3 rotm3(Axisang(toRad(320.0) / steps * i, m_upDir.xyz()));
-		Mat4 rotation(rotm3);
-		convexPoints[0][i] = localAxis * (rotation * p0);
-		convexPoints[1][i] = localAxis * (rotation * p1);
-	}
-
-	NewtonCollision* supportShape =
-		NewtonCreateConvexHull(world, steps * 2, &convexPoints[0][0][0], sizeof(Vec4), 0.0, 0, nullptr);
-	if(supportShape == nullptr)
-	{
-		ANKI_LOGE("NewtonCreateConvexHull() failed");
 		return ErrorCode::FUNCTION_FAILED;
 		return ErrorCode::FUNCTION_FAILED;
 	}
 	}
 
 
-	// Create the outer thick cylinder
-	Mat4 outerShapeRot(Mat3(Axisang(PI / 2.0, Vec3(0.0, 0.0, 1.0))));
-	Mat4 outerShapeMatrix = localAxis * outerShapeRot;
-	F32 capsuleHeight = m_height - m_stepHeight;
-	ANKI_ASSERT(capsuleHeight > 0.0);
-	m_sphereCastOrigin = capsuleHeight * 0.5 + m_stepHeight;
+	// Set some data
+	NewtonBody* body = m_newtonPlayer->GetBody();
+	NewtonBodySetUserData(body, this);
+	NewtonBodySetTransformCallback(body, onTransformUpdateCallback);
 
 
-	Vec4 transl(m_upDir * m_sphereCastOrigin);
-	transl.w() = 1.0;
-	outerShapeMatrix.setTranslationPart(transl);
-	outerShapeMatrix.transpose();
-
-	NewtonCollision* bodyCapsule = NewtonCreateCapsule(world, 0.25, 0.25, 0.5, 0, &outerShapeMatrix[0]);
-	if(bodyCapsule == nullptr)
-	{
-		ANKI_LOGE("NewtonCreateCapsule() failed");
-		return ErrorCode::FUNCTION_FAILED;
-	}
-
-	NewtonCollisionSetScale(bodyCapsule, capsuleHeight, m_outerRadius * 4.0, m_outerRadius * 4.0);
-
-	// Compound collision player controller
-	NewtonCollision* playerShape = NewtonCreateCompoundCollision(world, 0);
-	if(playerShape == nullptr)
-	{
-		ANKI_LOGE("NewtonCreateCompoundCollision() failed");
-		return ErrorCode::FUNCTION_FAILED;
-	}
-
-	NewtonCompoundCollisionBeginAddRemove(playerShape);
-	NewtonCompoundCollisionAddSubCollision(playerShape, supportShape);
-	NewtonCompoundCollisionAddSubCollision(playerShape, bodyCapsule);
-	NewtonCompoundCollisionEndAddRemove(playerShape);
-
-	// Create the kinematic body
-	Mat4 locationMatrix(Mat4::getIdentity());
-	locationMatrix.setTranslationPart(init.m_position.xyz1());
-	m_body = NewtonCreateKinematicBody(world, playerShape, &toNewton(locationMatrix)[0]);
-	if(m_body == nullptr)
-	{
-		ANKI_LOGE("NewtonCreateKinematicBody() failed");
-		return ErrorCode::FUNCTION_FAILED;
-	}
-
-	NewtonBodySetUserData(m_body, this);
-	NewtonBodySetTransformCallback(m_body, onTransformCallback);
-	NewtonBodySetMaterialGroupID(m_body, NewtonMaterialGetDefaultGroupID(m_world->getNewtonWorld()));
-
-	// Players must have weight, otherwise they are infinitely strong when they collide
-	NewtonCollision* shape = NewtonBodyGetCollision(m_body);
-	if(shape == nullptr)
-	{
-		ANKI_LOGE("NewtonBodyGetCollision() failed");
-		return ErrorCode::FUNCTION_FAILED;
-	}
-
-	NewtonBodySetMassProperties(m_body, init.m_mass, shape);
-	NewtonBodySetCollidable(m_body, true);
-
-	// Create yet another collision shape
-	F32 castHeight = capsuleHeight * 0.4;
-	F32 castRadius = min(m_innerRadius * 0.5, 0.05);
-
-	Vec4 q0(castRadius, 0.0, 0.0, 0.0);
-	Vec4 q1(castRadius, castHeight, 0.0, 0.0);
-	for(U i = 0; i < steps; ++i)
-	{
-		Mat3 rotm3(Axisang(toRad(320.0) / steps * i, m_upDir.xyz()));
-		Mat4 rotation(rotm3);
-		convexPoints[0][i] = localAxis * (rotation * q0);
-		convexPoints[1][i] = localAxis * (rotation * q1);
-	}
-	m_castingShape = NewtonCreateConvexHull(world, steps * 2, &convexPoints[0][0][0], sizeof(Vec4), 0.0, 0, nullptr);
-	if(m_castingShape == nullptr)
-	{
-		ANKI_LOGE("NewtonCreateConvexHull() failed");
-		return ErrorCode::FUNCTION_FAILED;
-	}
-
-	// Finish
-	m_supportShape =
-		NewtonCompoundCollisionGetCollisionFromNode(shape, NewtonCompoundCollisionGetNodeByIndex(shape, 0));
-	m_upperBodyShape =
-		NewtonCompoundCollisionGetCollisionFromNode(shape, NewtonCompoundCollisionGetNodeByIndex(shape, 1));
-
-	NewtonDestroyCollision(bodyCapsule);
-	NewtonDestroyCollision(supportShape);
-	NewtonDestroyCollision(playerShape);
+	dMatrix location(dGetIdentityMatrix());
+	location.m_posit.m_x = init.m_position.x();
+	location.m_posit.m_y = init.m_position.y();
+	location.m_posit.m_z = init.m_position.z();
+	NewtonBodySetMatrix(body, &location[0][0]);
 
 
 	return ErrorCode::NONE;
 	return ErrorCode::NONE;
 }
 }
 
 
-Vec4 PhysicsPlayerController::calculateDesiredOmega(const Vec4& frontDir, F32 dt) const
-{
-	Quat playerRotation;
-	NewtonBodyGetRotation(m_body, &playerRotation[0]);
-	playerRotation = toAnki(playerRotation);
-
-	Quat targetRotation;
-	targetRotation.setFrom2Vec3(m_frontDir.xyz(), frontDir.xyz());
-	return calcAverageOmega(playerRotation, targetRotation, 0.5 / dt);
-}
-
-Vec4 PhysicsPlayerController::calculateDesiredVelocity(
-	F32 forwardSpeed, F32 strafeSpeed, F32 verticalSpeed, const Vec4& gravity, F32 dt) const
-{
-	Mat4 matrix;
-	NewtonBodyGetMatrix(m_body, &matrix[0]);
-	matrix = toAnki(matrix);
-	matrix.setTranslationPart(Vec4(0.0, 0.0, 0.0, 1.0));
-
-	Vec4 updir(matrix * m_upDir);
-	Vec4 frontDir(matrix * m_frontDir);
-	Vec4 rightDir(frontDir.cross(updir));
-
-	Vec4 veloc(0.0);
-	Vec4 groundPlaneDir = m_groundPlane.xyz0();
-	if((verticalSpeed <= 0.0) && groundPlaneDir.getLengthSquared() > 0.0)
-	{
-		// Plane is supported by a ground plane, apply the player input velocity
-		if(groundPlaneDir.dot(updir) >= m_maxSlope)
-		{
-			// Player is in a legal slope, he is in full control of his movement
-			Vec4 bodyVeloc(0.0);
-			NewtonBodyGetVelocity(m_body, &bodyVeloc[0]);
-			veloc = updir * bodyVeloc.dot(updir) + gravity * dt + frontDir * forwardSpeed + rightDir * strafeSpeed
-				+ updir * verticalSpeed;
-
-			veloc += m_groundVelocity - updir * updir.dot(m_groundVelocity);
-
-			F32 speedLimitMag2 = forwardSpeed * forwardSpeed + strafeSpeed * strafeSpeed + verticalSpeed * verticalSpeed
-				+ m_groundVelocity.dot(m_groundVelocity) + 0.1;
-
-			F32 speedMag2 = veloc.getLengthSquared();
-			if(speedMag2 > speedLimitMag2)
-			{
-				veloc = veloc * sqrt(speedLimitMag2 / speedMag2);
-			}
-
-			F32 normalVeloc = groundPlaneDir.dot(veloc - m_groundVelocity);
-			if(normalVeloc < 0.0)
-			{
-				veloc -= groundPlaneDir * normalVeloc;
-			}
-		}
-		else
-		{
-			// Player is in an illegal ramp, he slides down hill an loses control of his movement
-			NewtonBodyGetVelocity(m_body, &veloc[0]);
-			veloc += updir * verticalSpeed;
-			veloc += gravity * dt;
-			F32 normalVeloc = groundPlaneDir.dot(veloc - m_groundVelocity);
-			if(normalVeloc < 0.0)
-			{
-				veloc -= groundPlaneDir * normalVeloc;
-			}
-		}
-	}
-	else
-	{
-		// Player is on free fall, only apply the gravity
-		NewtonBodyGetVelocity(m_body, &veloc[0]);
-		veloc += updir * verticalSpeed;
-		veloc += gravity * dt;
-	}
-
-	return veloc;
-}
-
-void PhysicsPlayerController::calculateVelocity(F32 dt)
-{
-	Vec4 omega(calculateDesiredOmega(m_forwardDir, dt));
-	Vec4 veloc(calculateDesiredVelocity(m_forwardSpeed, m_strafeSpeed, m_jumpSpeed, m_gravity, dt));
-
-	NewtonBodySetOmega(m_body, &omega[0]);
-	NewtonBodySetVelocity(m_body, &veloc[0]);
-
-	if(m_jumpSpeed > 0.0)
-	{
-		m_isJumping = true;
-	}
-}
-
-F32 PhysicsPlayerController::calculateContactKinematics(
-	const Vec4& veloc, const NewtonWorldConvexCastReturnInfo* contactInfo) const
-{
-	Vec4 contactVeloc(0.0);
-	if(contactInfo->m_hitBody)
-	{
-		NewtonBodyGetPointVelocity(contactInfo->m_hitBody, contactInfo->m_point, &contactVeloc[0]);
-	}
-
-	const F32 restitution = 0.0;
-	Vec4 normal(contactInfo->m_normal[0], contactInfo->m_normal[1], contactInfo->m_normal[2], 0.0);
-	F32 reboundVelocMag = -((veloc - contactVeloc).dot(normal)) * (1.0 + restitution);
-	return max(reboundVelocMag, 0.0f);
-}
-
-void PhysicsPlayerController::updateGroundPlane(Mat4& matrix, const Mat4& castMatrix, const Vec4& dst, int threadIndex)
-{
-	NewtonWorld* world = m_world->getNewtonWorld();
-
-	NewtonWorldConvexCastReturnInfo info;
-	CustomControllerConvexRayFilter filter;
-	filter.m_me = m_body;
-
-	F32 param = 10.0f;
-	NewtonWorldConvexCast(world,
-		&toNewton(castMatrix)[0],
-		reinterpret_cast<const F32*>(&dst),
-		m_castingShape,
-		&param,
-		&filter,
-		CustomControllerConvexRayFilter::prefilterCallback,
-		&info,
-		1,
-		threadIndex);
-
-	m_groundPlane = Vec4(0.0);
-	m_groundVelocity = Vec4(0.0);
-
-	if(filter.m_hitBody)
-	{
-		m_isJumping = false;
-
-		Vec4 castMatrixTransl = castMatrix.getTranslationPart().xyz0();
-
-		Vec4 supportPoint(castMatrixTransl + (dst - castMatrixTransl) * filter.m_intersectParam);
-
-		m_groundPlane = filter.m_hitNormal;
-		m_groundPlane.w() = -supportPoint.dot(filter.m_hitNormal);
-
-		NewtonBodyGetPointVelocity(filter.m_hitBody, &supportPoint[0], &m_groundVelocity[0]);
-
-		matrix.setTranslationPart(supportPoint.xyz1());
-	}
-}
-
-void PhysicsPlayerController::postUpdate(F32 dt, int threadIndex)
-{
-	Mat4 matrix;
-	Quat bodyRotation;
-	Vec4 veloc(0.0);
-	Vec4 omega(0.0);
-
-	NewtonWorld* world = m_world->getNewtonWorld();
-
-	calculateVelocity(dt);
-
-	// Get the body motion state
-	NewtonBodyGetMatrix(m_body, &matrix[0]);
-	matrix = toAnki(matrix);
-	NewtonBodyGetVelocity(m_body, &veloc[0]);
-	NewtonBodyGetOmega(m_body, &omega[0]);
-
-	// Integrate body angular velocity
-	NewtonBodyGetRotation(m_body, &bodyRotation[0]);
-	bodyRotation = toAnki(bodyRotation);
-	bodyRotation = integrateOmega(bodyRotation, omega, dt);
-	matrix.setRotationPart(Mat3(bodyRotation));
-
-	// Integrate linear velocity
-	F32 normalizedTimeLeft = 1.0;
-	F32 step = dt * veloc.getLength();
-	F32 descreteTimeStep = dt * (1.0 / DESCRETE_MOTION_STEPS);
-	U prevContactCount = 0;
-	CustomControllerConvexCastPreFilter castFilterData(m_body);
-	Array<NewtonWorldConvexCastReturnInfo, MAX_CONTACTS> prevInfo;
-
-	Vec4 updir(matrix.getRotationPart() * m_upDir.xyz(), 0.0);
-
-	Vec4 scale(0.0);
-	NewtonCollisionGetScale(m_upperBodyShape, &scale.x(), &scale.y(), &scale.z());
-	F32 radio = (m_outerRadius + m_restrainingDistance) * 4.0;
-	NewtonCollisionSetScale(m_upperBodyShape, m_height - m_stepHeight, radio, radio);
-
-	NewtonWorldConvexCastReturnInfo upConstraint;
-	memset(&upConstraint, 0, sizeof(upConstraint));
-	upConstraint.m_normal[0] = m_upDir.x();
-	upConstraint.m_normal[1] = m_upDir.y();
-	upConstraint.m_normal[2] = m_upDir.z();
-	upConstraint.m_normal[3] = m_upDir.w();
-
-	for(U j = 0; (j < MAX_INTERGRATION_STEPS) && (normalizedTimeLeft > 1.0e-5f); ++j)
-	{
-		if((veloc.getLengthSquared()) < 1.0e-6)
-		{
-			break;
-		}
-
-		F32 timetoImpact;
-		Array<NewtonWorldConvexCastReturnInfo, MAX_CONTACTS> info;
-
-		Vec4 destPosit(matrix.getTranslationPart().xyz0() + veloc * dt);
-		U contactCount = NewtonWorldConvexCast(world,
-			&matrix.getTransposed()[0],
-			&destPosit[0],
-			m_upperBodyShape,
-			&timetoImpact,
-			&castFilterData,
-			CustomControllerConvexCastPreFilter::prefilterCallback,
-			&info[0],
-			info.getSize(),
-			threadIndex);
-
-		if(contactCount > 0)
-		{
-			matrix.setTranslationPart(matrix.getTranslationPart() + veloc * (timetoImpact * dt));
-
-			if(timetoImpact > 0.0)
-			{
-				Vec4 tmp = matrix.getTranslationPart() - veloc * (CONTACT_SKIN_THICKNESS / veloc.getLength());
-				matrix.setTranslationPart(tmp.xyz1());
-			}
-
-			normalizedTimeLeft -= timetoImpact;
-
-			Array<F32, MAX_CONTACTS * 2> speed;
-			Array<F32, MAX_CONTACTS * 2> bounceSpeed;
-			Array<Vec4, MAX_CONTACTS * 2> bounceNormal;
-
-			for(U i = 1; i < contactCount; ++i)
-			{
-				Vec4 n0(info[i - 1].m_normal);
-
-				for(U j = 0; j < i; ++j)
-				{
-					Vec4 n1(info[j].m_normal);
-					if((n0.dot(n1)) > 0.9999)
-					{
-						info[i] = info[contactCount - 1];
-						--i;
-						--contactCount;
-						break;
-					}
-				}
-			}
-
-			U count = 0;
-			if(!m_isJumping)
-			{
-				Vec4 matTls = matrix.getTranslationPart();
-				upConstraint.m_point[0] = matTls.x();
-				upConstraint.m_point[1] = matTls.y();
-				upConstraint.m_point[2] = matTls.z();
-				upConstraint.m_point[3] = matTls.w();
-
-				speed[count] = 0.0;
-				bounceNormal[count] = Vec4(upConstraint.m_normal);
-				bounceSpeed[count] = calculateContactKinematics(veloc, &upConstraint);
-				++count;
-			}
-
-			for(U i = 0; i < contactCount; ++i)
-			{
-				speed[count] = 0.0;
-				bounceNormal[count] = Vec4(info[i].m_normal);
-				bounceSpeed[count] = calculateContactKinematics(veloc, &info[i]);
-				++count;
-			}
-
-			for(U i = 0; i < prevContactCount; ++i)
-			{
-				speed[count] = 0.0;
-				bounceNormal[count] = Vec4(prevInfo[i].m_normal);
-				bounceSpeed[count] = calculateContactKinematics(veloc, &prevInfo[i]);
-				++count;
-			}
-
-			F32 residual = 10.0;
-			Vec4 auxBounceVeloc(0.0);
-			for(U i = 0; (i < MAX_SOLVER_ITERATIONS) && (residual > 1.0e-3); ++i)
-			{
-				residual = 0.0;
-				for(U k = 0; k < count; ++k)
-				{
-					Vec4 normal(bounceNormal[k]);
-					F32 v = bounceSpeed[k] - normal.dot(auxBounceVeloc);
-					F32 x = speed[k] + v;
-					if(x < 0.0)
-					{
-						v = 0.0;
-						x = 0.0;
-					}
-
-					if(absolute(v) > residual)
-					{
-						residual = absolute(v);
-					}
-
-					auxBounceVeloc += normal * (x - speed[k]);
-					speed[k] = x;
-				}
-			}
-
-			Vec4 velocStep(0.0);
-			for(U i = 0; i < count; ++i)
-			{
-				Vec4 normal(bounceNormal[i]);
-				velocStep += normal * speed[i];
-			}
-
-			veloc += velocStep;
-
-			F32 velocMag2 = velocStep.getLengthSquared();
-			if(velocMag2 < 1.0e-6)
-			{
-				F32 advanceTime = min(descreteTimeStep, normalizedTimeLeft * dt);
-
-				Vec4 tmp = matrix.getTranslationPart() + veloc * advanceTime;
-				matrix.setTranslationPart(tmp.xyz1());
-
-				normalizedTimeLeft -= advanceTime / dt;
-			}
-
-			prevContactCount = contactCount;
-			memcpy(&prevInfo[0], &info[0], prevContactCount * sizeof(NewtonWorldConvexCastReturnInfo));
-		}
-		else
-		{
-			matrix.setTranslationPart(destPosit.xyz1());
-			break;
-		}
-	}
-
-	NewtonCollisionSetScale(m_upperBodyShape, scale.x(), scale.y(), scale.z());
-
-	// determine if player is standing on some plane
-	Mat4 supportMatrix(matrix);
-	Vec4 tmp = supportMatrix.getTranslationPart() + updir * m_sphereCastOrigin;
-	supportMatrix.setTranslationPart(tmp.xyz1());
-
-	if(m_isJumping)
-	{
-		Vec4 dst = matrix.getTranslationPart().xyz0();
-		updateGroundPlane(matrix, supportMatrix, dst, threadIndex);
-	}
-	else
-	{
-		step = absolute(updir.dot(veloc * dt));
-		F32 castDist = (m_groundPlane.getLengthSquared() > 0.0) ? m_stepHeight : step;
-		Vec4 tmp = matrix.getTranslationPart() - updir * (castDist * 2.0);
-		Vec4 dst = tmp.xyz0();
-
-		updateGroundPlane(matrix, supportMatrix, dst, threadIndex);
-	}
-
-	// set player velocity, position and orientation
-	NewtonBodySetVelocity(m_body, &veloc[0]);
-	NewtonBodySetMatrix(m_body, &toNewton(matrix)[0]);
-}
-
-void PhysicsPlayerController::postUpdateKernelCallback(NewtonWorld* const world, void* const context, int threadIndex)
-{
-	PhysicsPlayerController* x = static_cast<PhysicsPlayerController*>(context);
-	x->postUpdate(x->m_world->getDeltaTime(), threadIndex);
-}
-
 void PhysicsPlayerController::moveToPosition(const Vec4& position)
 void PhysicsPlayerController::moveToPosition(const Vec4& position)
 {
 {
-	Mat4 trf;
-	NewtonBodyGetMatrix(m_body, &trf[0]);
-	trf.transpose();
-	trf.setTranslationPart(position.xyz1());
-	NewtonBodySetMatrix(m_body, &trf[0]);
-}
-
-void PhysicsPlayerController::onTransformCallback(
-	const NewtonBody* const body, const dFloat* const matrix, int /*threadIndex*/)
-{
-	ANKI_ASSERT(body);
-	ANKI_ASSERT(matrix);
-
-	Mat4 trf;
-	memcpy(&trf, matrix, sizeof(Mat4));
-
-	void* ud = NewtonBodyGetUserData(body);
-	ANKI_ASSERT(ud);
-	PhysicsPlayerController* self = static_cast<PhysicsPlayerController*>(ud);
-	self->onTransform(trf);
-}
-
-void PhysicsPlayerController::onTransform(Mat4 trf)
-{
-	if(trf != m_prevTrf)
-	{
-		m_prevTrf = trf;
-		trf.transpose();
-
-		m_trf = Transform(trf);
-		m_updated = true;
-	}
+	ANKI_ASSERT(!"TODO");
 }
 }
 
 
 } // end namespace anki
 } // end namespace anki

+ 35 - 52
src/anki/physics/PhysicsPlayerController.h

@@ -6,6 +6,7 @@
 #pragma once
 #pragma once
 
 
 #include <anki/physics/PhysicsObject.h>
 #include <anki/physics/PhysicsObject.h>
+#include <CustomPlayerControllerManager.h>
 
 
 namespace anki
 namespace anki
 {
 {
@@ -13,6 +14,21 @@ namespace anki
 /// @addtogroup physics
 /// @addtogroup physics
 /// @{
 /// @{
 
 
+/// The implementation of the Newton manager.
+class CharacterControllerManager : public CustomPlayerControllerManager
+{
+public:
+	PhysicsWorld* m_world;
+
+	CharacterControllerManager(PhysicsWorld* world);
+
+	~CharacterControllerManager()
+	{
+	}
+
+	void ApplyPlayerMove(CustomPlayerController* const controller, dFloat timestep);
+};
+
 /// Init info for PhysicsPlayerController.
 /// Init info for PhysicsPlayerController.
 class PhysicsPlayerControllerInitInfo
 class PhysicsPlayerControllerInitInfo
 {
 {
@@ -28,6 +44,8 @@ public:
 /// A player controller that walks the world.
 /// A player controller that walks the world.
 class PhysicsPlayerController final : public PhysicsObject
 class PhysicsPlayerController final : public PhysicsObject
 {
 {
+	friend class CharacterControllerManager;
+
 public:
 public:
 	PhysicsPlayerController(PhysicsWorld* world)
 	PhysicsPlayerController(PhysicsWorld* world)
 		: PhysicsObject(PhysicsObjectType::PLAYER_CONTROLLER, world)
 		: PhysicsObject(PhysicsObjectType::PLAYER_CONTROLLER, world)
@@ -56,69 +74,34 @@ public:
 		return m_trf;
 		return m_trf;
 	}
 	}
 
 
-anki_internal:
-	/// Called by Newton thread to update the controller.
-	static void postUpdateKernelCallback(NewtonWorld* const world, void* const context, int threadIndex);
-
 private:
 private:
-	Vec4 m_upDir;
-	Vec4 m_frontDir;
-	Vec4 m_groundPlane;
-	Vec4 m_groundVelocity;
-	F32 m_innerRadius;
-	F32 m_outerRadius;
-	F32 m_height;
-	F32 m_stepHeight;
-	F32 m_maxSlope;
-	F32 m_sphereCastOrigin;
-	F32 m_restrainingDistance;
-	Bool8 m_isJumping;
-	NewtonBody* m_body;
-	NewtonCollision* m_castingShape;
-	NewtonCollision* m_supportShape;
-	NewtonCollision* m_upperBodyShape;
+	CustomPlayerController* m_newtonPlayer = nullptr;
+	Transform m_trf = Transform::getIdentity();
+	Bool m_updated = true;
 
 
 	// State
 	// State
 	F32 m_forwardSpeed = 0.0;
 	F32 m_forwardSpeed = 0.0;
 	F32 m_strafeSpeed = 0.0;
 	F32 m_strafeSpeed = 0.0;
 	F32 m_jumpSpeed = 0.0;
 	F32 m_jumpSpeed = 0.0;
 	Vec4 m_forwardDir = Vec4(0.0, 0.0, -1.0, 0.0);
 	Vec4 m_forwardDir = Vec4(0.0, 0.0, -1.0, 0.0);
-	Vec4 m_gravity;
 
 
-	// Motion state
-	Bool8 m_updated = true;
-	Transform m_trf = {Transform::getIdentity()};
-	Mat4 m_prevTrf = {Mat4::getIdentity()};
-
-	static constexpr F32 MIN_RESTRAINING_DISTANCE = 1.0e-2;
-	static constexpr U DESCRETE_MOTION_STEPS = 8;
-	static constexpr U MAX_CONTACTS = 32;
-	static constexpr U MAX_INTERGRATION_STEPS = 8;
-	static constexpr F32 CONTACT_SKIN_THICKNESS = 0.025;
-	static constexpr U MAX_SOLVER_ITERATIONS = 16;
-
-	void setClimbSlope(F32 ang)
+	static void onTransformUpdateCallback(const NewtonBody* body, const dFloat* matrix, int threadIndex)
 	{
 	{
-		ANKI_ASSERT(ang >= 0.0);
-		m_maxSlope = cos(ang);
+		ANKI_ASSERT(body && matrix);
+		Transform trf = Transform(toAnki(dMatrix(matrix)));
+		void* ud = NewtonBodyGetUserData(body);
+		ANKI_ASSERT(ud);
+		static_cast<PhysicsPlayerController*>(ud)->onTransformUpdate(trf);
 	}
 	}
 
 
-	Vec4 calculateDesiredOmega(const Vec4& headingAngle, F32 dt) const;
-
-	Vec4 calculateDesiredVelocity(
-		F32 forwardSpeed, F32 strafeSpeed, F32 verticalSpeed, const Vec4& gravity, F32 dt) const;
-
-	void calculateVelocity(F32 dt);
-
-	F32 calculateContactKinematics(const Vec4& veloc, const NewtonWorldConvexCastReturnInfo* contactInfo) const;
-
-	void updateGroundPlane(Mat4& matrix, const Mat4& castMatrix, const Vec4& dst, int threadIndex);
-
-	void postUpdate(F32 dt, int threadIndex);
-
-	static void onTransformCallback(const NewtonBody* const body, const dFloat* const matrix, int threadIndex);
-
-	void onTransform(Mat4 matrix);
+	void onTransformUpdate(const Transform& trf)
+	{
+		if(trf != m_trf)
+		{
+			m_updated = true;
+			m_trf = trf;
+		}
+	}
 };
 };
 /// @}
 /// @}
 
 

+ 4 - 33
src/anki/physics/PhysicsWorld.cpp

@@ -74,6 +74,9 @@ Error PhysicsWorld::create(AllocAlignedCallback allocCb, void* allocCbData)
 	// Set the simplified solver mode (faster but less accurate)
 	// Set the simplified solver mode (faster but less accurate)
 	NewtonSetSolverModel(m_world, 1);
 	NewtonSetSolverModel(m_world, 1);
 
 
+	// Create the character controller manager. Newton needs it's own allocators
+	m_playerManager = new CharacterControllerManager(this);
+
 	// Create scene collision
 	// Create scene collision
 	m_sceneCollision = NewtonCreateSceneCollision(m_world, 0);
 	m_sceneCollision = NewtonCreateSceneCollision(m_world, 0);
 	Mat4 trf = Mat4::getIdentity();
 	Mat4 trf = Mat4::getIdentity();
@@ -83,9 +86,6 @@ Error PhysicsWorld::create(AllocAlignedCallback allocCb, void* allocCbData)
 	NewtonDestroyCollision(m_sceneCollision); // destroy old scene
 	NewtonDestroyCollision(m_sceneCollision); // destroy old scene
 	m_sceneCollision = NewtonBodyGetCollision(m_sceneBody);
 	m_sceneCollision = NewtonBodyGetCollision(m_sceneBody);
 
 
-	// Set the post update listener
-	NewtonWorldAddPostListener(m_world, "world", this, postUpdateCallback, destroyCallback);
-
 	// Set callbacks
 	// Set callbacks
 	NewtonMaterialSetCollisionCallback(m_world,
 	NewtonMaterialSetCollisionCallback(m_world,
 		NewtonMaterialGetDefaultGroupID(m_world),
 		NewtonMaterialGetDefaultGroupID(m_world),
@@ -126,43 +126,14 @@ void PhysicsWorld::cleanupMarkedForDeletion()
 		// Remove from objects marked for deletion
 		// Remove from objects marked for deletion
 		m_forDeletion.erase(m_alloc, it);
 		m_forDeletion.erase(m_alloc, it);
 
 
-		// Remove from player controllers
-		if(obj->getType() == PhysicsObjectType::PLAYER_CONTROLLER)
-		{
-			auto it2 = m_playerControllers.getBegin();
-			for(; it2 != m_playerControllers.getEnd(); ++it2)
-			{
-				PhysicsObject* obj2 = *it2;
-				if(obj2 == obj)
-				{
-					break;
-				}
-			}
-
-			ANKI_ASSERT(it2 != m_playerControllers.getEnd());
-			m_playerControllers.erase(m_alloc, it2);
-		}
-
 		// Finaly, delete it
 		// Finaly, delete it
 		m_alloc.deleteInstance(obj);
 		m_alloc.deleteInstance(obj);
 	}
 	}
 }
 }
 
 
-void PhysicsWorld::postUpdate(F32 dt)
-{
-	for(PhysicsPlayerController* player : m_playerControllers)
-	{
-		NewtonDispachThreadJob(m_world, PhysicsPlayerController::postUpdateKernelCallback, player);
-	}
-}
-
 void PhysicsWorld::registerObject(PhysicsObject* ptr)
 void PhysicsWorld::registerObject(PhysicsObject* ptr)
 {
 {
-	if(ptr->getType() == PhysicsObjectType::PLAYER_CONTROLLER)
-	{
-		LockGuard<Mutex> lock(m_mtx);
-		m_playerControllers.pushBack(m_alloc, static_cast<PhysicsPlayerController*>(ptr));
-	}
+	// TODO Remove
 }
 }
 
 
 void PhysicsWorld::onContactCallback(const NewtonJoint* contactJoint, F32 timestep, int threadIndex)
 void PhysicsWorld::onContactCallback(const NewtonJoint* contactJoint, F32 timestep, int threadIndex)

+ 12 - 11
src/anki/physics/PhysicsWorld.h

@@ -11,6 +11,9 @@
 namespace anki
 namespace anki
 {
 {
 
 
+// Forward
+class CharacterControllerManager;
+
 /// @addtogroup physics
 /// @addtogroup physics
 /// @{
 /// @{
 
 
@@ -37,7 +40,7 @@ public:
 		return m_gravity;
 		return m_gravity;
 	}
 	}
 
 
-#ifdef ANKI_BUILD
+anki_internal:
 	NewtonWorld* getNewtonWorld() const
 	NewtonWorld* getNewtonWorld() const
 	{
 	{
 		ANKI_ASSERT(m_world);
 		ANKI_ASSERT(m_world);
@@ -60,7 +63,12 @@ public:
 		LockGuard<Mutex> lock(m_mtx);
 		LockGuard<Mutex> lock(m_mtx);
 		m_forDeletion.pushBack(m_alloc, obj);
 		m_forDeletion.pushBack(m_alloc, obj);
 	}
 	}
-#endif
+
+	CharacterControllerManager& getCharacterControllerManager()
+	{
+		ANKI_ASSERT(m_playerManager);
+		return *m_playerManager;
+	}
 
 
 private:
 private:
 	HeapAllocator<U8> m_alloc;
 	HeapAllocator<U8> m_alloc;
@@ -70,7 +78,8 @@ private:
 	Vec4 m_gravity = Vec4(0.0, -9.8, 0.0, 0.0);
 	Vec4 m_gravity = Vec4(0.0, -9.8, 0.0, 0.0);
 	F32 m_dt = 0.0;
 	F32 m_dt = 0.0;
 
 
-	List<PhysicsPlayerController*> m_playerControllers;
+	/// @note Don't delete it. Newton will
+	CharacterControllerManager* m_playerManager = nullptr;
 
 
 	Mutex m_mtx;
 	Mutex m_mtx;
 	List<PhysicsObject*> m_forDeletion;
 	List<PhysicsObject*> m_forDeletion;
@@ -80,14 +89,6 @@ private:
 
 
 	void cleanupMarkedForDeletion();
 	void cleanupMarkedForDeletion();
 
 
-	/// Custom update
-	static void postUpdateCallback(const NewtonWorld* const world, void* const listenerUserData, F32 dt)
-	{
-		static_cast<PhysicsWorld*>(listenerUserData)->postUpdate(dt);
-	}
-
-	void postUpdate(F32 dt);
-
 	static void destroyCallback(const NewtonWorld* const world, void* const listenerUserData)
 	static void destroyCallback(const NewtonWorld* const world, void* const listenerUserData)
 	{
 	{
 	}
 	}