<commit_before>#include <Zmey/Physics/PhysicsEngine.h>

#include <PhysX/PxPhysics.h>
#include <PhysX/PxPhysicsAPI.h>
#include <PhysXShared/foundation/PxAllocatorCallback.h>
#include <PhysX/common/PxTolerancesScale.h>
#include <PhysX/pvd/PxPvdSceneClient.h>

#include <Zmey/Logging.h>
#include <Zmey/Modules.h>
#include <Zmey/Components/TransformManager.h>
#include <Zmey/Physics/PhysicsActor.h>
#include <Zmey/World.h>

#include <Windows.h> // Included for GetTempPath; TODO: move to a platform-indepedent header

namespace Zmey
{
namespace Physics
{

class PhysicsAllocator : public physx::PxAllocatorCallback
{
public:
	virtual void* allocate(size_t size, const char* typeName, const char* filename, int line) override
	{
		return Zmey::GAllocator->Malloc(size, 16u);
	}
	virtual void deallocate(void* ptr) override
	{
		Zmey::GAllocator->Free(ptr);
	}
};

class PhysicsErrorReporter : public physx::PxErrorCallback
{
	inline Zmey::LogSeverity PxErrorCodeToSeverity(physx::PxErrorCode::Enum error)
	{
		switch (error)
		{
			case physx::PxErrorCode::eDEBUG_INFO:
				return Zmey::LogSeverity::Debug;
			case physx::PxErrorCode::eDEBUG_WARNING:
			case physx::PxErrorCode::ePERF_WARNING:
				return Zmey::LogSeverity::Warning;
			case physx::PxErrorCode::eINTERNAL_ERROR:
			case physx::PxErrorCode::eINVALID_OPERATION:
			case physx::PxErrorCode::eINVALID_PARAMETER:
			case physx::PxErrorCode::eOUT_OF_MEMORY:
				return Zmey::LogSeverity::Error;
			case physx::PxErrorCode::eABORT:
				return Zmey::LogSeverity::Fatal;
			default:
				NOT_REACHED();
				return Zmey::LogSeverity::Fatal;
		}
	}
	virtual void reportError(physx::PxErrorCode::Enum code, const char* message, const char* file, int line) override
	{
		Zmey::GLogHandler->WriteLog(PxErrorCodeToSeverity(code), "Physics", message);
	}
};

class PhysicsCpuDispatcher : public physx::PxCpuDispatcher
{
public:
	static void CPUJobEntryPoint(void* data)
	{
		physx::PxBaseTask* task = reinterpret_cast<physx::PxBaseTask*>(data);

		task->run();
		task->release();
	}

	virtual void submitTask(physx::PxBaseTask& task) override
	{
		Job::JobDecl job{ CPUJobEntryPoint, &task };
		Zmey::Modules.JobSystem.RunJobs("PhysX CPU Task", &job, 1, nullptr);
	}

	virtual uint32_t getWorkerCount() const override
	{
		return 3; // TODO: get this from somewhere
	}
};

const float PhysicsEngine::TimeStep = 1 / 60.f;

PhysicsEngine::PhysicsEngine()
	: m_Allocator(StaticAlloc<PhysicsAllocator>())
	, m_ErrorReporter(StaticAlloc<PhysicsErrorReporter>())
	, m_CpuDispatcher(StaticAlloc<PhysicsCpuDispatcher>())
	, m_World(nullptr)
	, m_TimeAccumulator(0.f)
{
	m_Foundation.reset(PxCreateFoundation(PX_FOUNDATION_VERSION, *m_Allocator, *m_ErrorReporter));
	ASSERT_FATAL(m_Foundation);

	physx::PxTolerancesScale scale;
#if defined(_DEBUG)
	bool recordMemoryAllocations = true;
	CreateDebuggerConnection();
#elif defined(NDEBUG)
	bool recordMemoryAllocations = false;
#endif
	m_Physics.reset(PxCreatePhysics(PX_PHYSICS_VERSION, *m_Foundation, scale, recordMemoryAllocations, m_VisualDebugger.get()));
	ASSERT_FATAL(m_Physics);

	physx::PxSceneDesc sceneDesc(m_Physics->getTolerancesScale());
	sceneDesc.gravity = physx::PxVec3(0.0f, -9.81f, 0.0f);

	sceneDesc.cpuDispatcher = m_CpuDispatcher;
	sceneDesc.filterShader = physx::PxDefaultSimulationFilterShader;

	sceneDesc.frictionType = physx::PxFrictionType::eTWO_DIRECTIONAL;
	sceneDesc.frictionType = physx::PxFrictionType::eONE_DIRECTIONAL;
	sceneDesc.flags |= physx::PxSceneFlag::eENABLE_PCM;
	sceneDesc.flags |= physx::PxSceneFlag::eENABLE_STABILIZATION;
	sceneDesc.flags |= physx::PxSceneFlag::eENABLE_ACTIVETRANSFORMS;
	sceneDesc.flags |= physx::PxSceneFlag::eSUPPRESS_EAGER_SCENE_QUERY_REFIT;

	sceneDesc.broadPhaseType = physx::PxBroadPhaseType::eSAP; // TODO: Switch to MBP

	m_Scene.reset(m_Physics->createScene(sceneDesc));
	ASSERT_FATAL(m_Scene);

	physx::PxSceneWriteLock scopedLock(*m_Scene);
	m_Scene->setVisualizationParameter(physx::PxVisualizationParameter::eSCALE, 1.f);
	m_Scene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);
	LOG(Info, Physics, "Physics system initialized!");

	physx::PxPvdSceneClient* pvdClient = m_Scene->getScenePvdClient();
	if (pvdClient)
	{
		pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS, true);
		pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_CONTACTS, true);
		pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES, true);
	}
}

PhysicsEngine::~PhysicsEngine()
{}

void PhysicsEngine::CreateDebuggerConnection()
{
#ifdef _DEBUG
	//The normal way to connect to pvd.  PVD needs to be running at the time this function is called.
	//We don't worry about the return value because we are already registered as a listener for connections
	//and thus our onPvdConnected call will take care of setting up our basic connection state.
	char ip[] = "127.0.0.1";
	m_Transport.reset(physx::PxDefaultPvdSocketTransportCreate(ip, 5425, 1000));
	if (!m_Transport)
	{
		return;
	}

	//Use these flags for a clean profile trace with minimal overhead
	physx::PxPvdInstrumentationFlags flags = physx::PxPvdInstrumentationFlag::eALL;

	m_VisualDebugger.reset(physx::PxCreatePvd(*m_Foundation));
	m_VisualDebugger->connect(*m_Transport, flags);
#endif
}

void PhysicsEngine::Simulate(float deltaTime)
{
	m_TimeAccumulator += deltaTime;
	if (m_TimeAccumulator < PhysicsEngine::TimeStep)
	{
		return;
	}

	m_TimeAccumulator -= PhysicsEngine::TimeStep;
	TEMP_ALLOCATOR_SCOPE;
	uint32_t scratchMemorySize = 1024 * 1024; // 1mb
	tmp::unique_array<uint8_t> scratchMemory = tmp::make_unique_array<uint8_t>(scratchMemorySize);
	{
		physx::PxSceneWriteLock writeLock(*m_Scene);
		m_Scene->simulate(PhysicsEngine::TimeStep, nullptr, scratchMemory.get(), scratchMemorySize);
	}
	m_HasIssuedSimulate = true;
}

inline void SetZmeyTransformFromPhysx(Zmey::Components::TransformInstance& transform, const physx::PxTransform& pxTransform)
{
	transform.Position().x = pxTransform.p.x;
	transform.Position().y = pxTransform.p.y;
	transform.Position().z = pxTransform.p.z;
	transform.Rotation().x = pxTransform.q.x;
	transform.Rotation().y = pxTransform.q.y;
	transform.Rotation().z = pxTransform.q.z;
	transform.Rotation().w = pxTransform.q.w;
}

inline void SetPhysxTransformFromZmey(physx::PxTransform& pxTransform, const Zmey::Components::TransformInstance& transform)
{
	pxTransform.p.x = transform.Position().x;
	pxTransform.p.y = transform.Position().y;
	pxTransform.p.z = transform.Position().z;
	pxTransform.q.x = transform.Rotation().x;
	pxTransform.q.y = transform.Rotation().y;
	pxTransform.q.z = transform.Rotation().z;
	pxTransform.q.w = transform.Rotation().w;
}

void PhysicsEngine::FetchResults()
{
	if (!m_HasIssuedSimulate)
	{
		return;
	}

	{
		physx::PxSceneWriteLock writeLock(*m_Scene);

		physx::PxU32 error(physx::PxErrorCode::eNO_ERROR);
		m_Scene->fetchResults(true, &error);
		ASSERT(error == physx::PxErrorCode::eNO_ERROR);
	}
	m_HasIssuedSimulate = false;

	physx::PxU32 activeTransformsCount = -1;
	auto activeTransforms = m_Scene->getActiveTransforms(activeTransformsCount);
	auto& transformManager = m_World->GetManager<Zmey::Components::TransformManager>();
	for (physx::PxU32 i = 0; i < activeTransformsCount; ++i)
	{
		auto entityId = static_cast<Zmey::EntityId>(reinterpret_cast<uint64_t>(activeTransforms[i].userData));
		auto transform = transformManager.Lookup(entityId);
		// TODO This currently copies transforms as an array of structs; change to SoA.
		SetZmeyTransformFromPhysx(transform, activeTransforms[i].actor2World);
	}
}

PhysicsEngine::GeometryPtr PhysicsEngine::CreateBoxGeometry(float width, float height, float depth) const
{
	physx::PxBoxGeometry box(width / 2, height / 2, depth / 2);
	GeometryPtr result(new physx::PxGeometryHolder(std::move(box)));
	return result;
}
PhysicsEngine::GeometryPtr PhysicsEngine::CreateSphereGeometry(float radius) const
{
	physx::PxSphereGeometry sphere(radius);
	GeometryPtr result(new physx::PxGeometryHolder(std::move(sphere)));
	return result;
}
PhysicsEngine::GeometryPtr PhysicsEngine::CreateCapsuleGeometry(float radius, float height) const
{
	physx::PxCapsuleGeometry capsule(radius, height / 2);
	GeometryPtr result(new physx::PxGeometryHolder(std::move(capsule)));
	return result;
}

stl::unique_ptr<PhysicsActor> PhysicsEngine::CreatePhysicsActor(EntityId entityId, const PhysicsActorDescription& actorDescription)
{
	const CombinedMaterialInfo* material = FindMaterial(actorDescription.Material);
	ASSERT(material);
	physx::PxRigidActor* actor = nullptr;
	auto actorTransform = m_World->GetManager<Zmey::Components::TransformManager>().Lookup(entityId);
	physx::PxTransform currentTransform;
	SetPhysxTransformFromZmey(currentTransform, actorTransform);
	if (actorDescription.IsStatic)
	{
		actor = m_Physics->createRigidStatic(currentTransform);
	}
	else
	{
		actor = m_Physics->createRigidDynamic(currentTransform);
	}
	physx::PxShapeFlags flags = physx::PxShapeFlag::eSIMULATION_SHAPE | physx::PxShapeFlag::eVISUALIZATION |
		static_cast<physx::PxShapeFlag::Enum>(actorDescription.IsTrigger * physx::PxShapeFlag::eTRIGGER_SHAPE) |
		static_cast<physx::PxShapeFlag::Enum>(!actorDescription.IsTrigger * physx::PxShapeFlag::eSCENE_QUERY_SHAPE);
	physx::PxShape* shape = m_Physics->createShape(actorDescription.Geometry->any(), *material->PhysxMaterial, true, flags);
	actor->attachShape(*shape);
	actor->userData = reinterpret_cast<void*>(static_cast<uint64_t>(entityId));
	shape->release();
	m_Scene->addActor(*actor);

	stl::unique_ptr<Zmey::Physics::PhysicsActor> physicsActor(new Zmey::Physics::PhysicsActor(*actor, actorDescription.IsStatic));
	return physicsActor;
}
void PhysicsEngine::CreatePhysicsMaterial(Zmey::Name name, const PhysicsMaterialDescription& description)
{
	auto material = m_Physics->createMaterial(description.Friction, description.Friction, description.Restitution);
	m_Materials.push_back(std::make_pair(name, CombinedMaterialInfo{ material, description }));
}

const PhysicsEngine::CombinedMaterialInfo* PhysicsEngine::FindMaterial(Zmey::Name name) const
{
	auto it = std::find_if(m_Materials.begin(), m_Materials.end(), [name](const std::pair<Zmey::Name, CombinedMaterialInfo>& materialNamePair)
	{
		return materialNamePair.first == name;
	});
	if (it != m_Materials.end())
	{
		return &it->second;
	}
	return nullptr;
}

}

}<commit_msg>Fixed physx need of 16 kb aligned scratch memory<commit_after>#include <Zmey/Physics/PhysicsEngine.h>

#include <PhysX/PxPhysics.h>
#include <PhysX/PxPhysicsAPI.h>
#include <PhysXShared/foundation/PxAllocatorCallback.h>
#include <PhysX/common/PxTolerancesScale.h>
#include <PhysX/pvd/PxPvdSceneClient.h>

#include <Zmey/Logging.h>
#include <Zmey/Modules.h>
#include <Zmey/Components/TransformManager.h>
#include <Zmey/Physics/PhysicsActor.h>
#include <Zmey/World.h>

#include <Windows.h> // Included for GetTempPath; TODO: move to a platform-indepedent header

namespace Zmey
{
namespace Physics
{

class PhysicsAllocator : public physx::PxAllocatorCallback
{
public:
	virtual void* allocate(size_t size, const char* typeName, const char* filename, int line) override
	{
		return Zmey::GAllocator->Malloc(size, 16u);
	}
	virtual void deallocate(void* ptr) override
	{
		Zmey::GAllocator->Free(ptr);
	}
};

class PhysicsErrorReporter : public physx::PxErrorCallback
{
	inline Zmey::LogSeverity PxErrorCodeToSeverity(physx::PxErrorCode::Enum error)
	{
		switch (error)
		{
			case physx::PxErrorCode::eDEBUG_INFO:
				return Zmey::LogSeverity::Debug;
			case physx::PxErrorCode::eDEBUG_WARNING:
			case physx::PxErrorCode::ePERF_WARNING:
				return Zmey::LogSeverity::Warning;
			case physx::PxErrorCode::eINTERNAL_ERROR:
			case physx::PxErrorCode::eINVALID_OPERATION:
			case physx::PxErrorCode::eINVALID_PARAMETER:
			case physx::PxErrorCode::eOUT_OF_MEMORY:
				return Zmey::LogSeverity::Error;
			case physx::PxErrorCode::eABORT:
				return Zmey::LogSeverity::Fatal;
			default:
				NOT_REACHED();
				return Zmey::LogSeverity::Fatal;
		}
	}
	virtual void reportError(physx::PxErrorCode::Enum code, const char* message, const char* file, int line) override
	{
		Zmey::GLogHandler->WriteLog(PxErrorCodeToSeverity(code), "Physics", message);
	}
};

class PhysicsCpuDispatcher : public physx::PxCpuDispatcher
{
public:
	static void CPUJobEntryPoint(void* data)
	{
		physx::PxBaseTask* task = reinterpret_cast<physx::PxBaseTask*>(data);

		task->run();
		task->release();
	}

	virtual void submitTask(physx::PxBaseTask& task) override
	{
		Job::JobDecl job{ CPUJobEntryPoint, &task };
		Zmey::Modules.JobSystem.RunJobs("PhysX CPU Task", &job, 1, nullptr);
	}

	virtual uint32_t getWorkerCount() const override
	{
		return 3; // TODO: get this from somewhere
	}
};

const float PhysicsEngine::TimeStep = 1 / 60.f;

PhysicsEngine::PhysicsEngine()
	: m_Allocator(StaticAlloc<PhysicsAllocator>())
	, m_ErrorReporter(StaticAlloc<PhysicsErrorReporter>())
	, m_CpuDispatcher(StaticAlloc<PhysicsCpuDispatcher>())
	, m_World(nullptr)
	, m_TimeAccumulator(0.f)
{
	m_Foundation.reset(PxCreateFoundation(PX_FOUNDATION_VERSION, *m_Allocator, *m_ErrorReporter));
	ASSERT_FATAL(m_Foundation);

	physx::PxTolerancesScale scale;
#if defined(_DEBUG)
	bool recordMemoryAllocations = true;
	CreateDebuggerConnection();
#elif defined(NDEBUG)
	bool recordMemoryAllocations = false;
#endif
	m_Physics.reset(PxCreatePhysics(PX_PHYSICS_VERSION, *m_Foundation, scale, recordMemoryAllocations, m_VisualDebugger.get()));
	ASSERT_FATAL(m_Physics);

	physx::PxSceneDesc sceneDesc(m_Physics->getTolerancesScale());
	sceneDesc.gravity = physx::PxVec3(0.0f, -9.81f, 0.0f);

	sceneDesc.cpuDispatcher = m_CpuDispatcher;
	sceneDesc.filterShader = physx::PxDefaultSimulationFilterShader;

	sceneDesc.frictionType = physx::PxFrictionType::eTWO_DIRECTIONAL;
	sceneDesc.frictionType = physx::PxFrictionType::eONE_DIRECTIONAL;
	sceneDesc.flags |= physx::PxSceneFlag::eENABLE_PCM;
	sceneDesc.flags |= physx::PxSceneFlag::eENABLE_STABILIZATION;
	sceneDesc.flags |= physx::PxSceneFlag::eENABLE_ACTIVETRANSFORMS;
	sceneDesc.flags |= physx::PxSceneFlag::eSUPPRESS_EAGER_SCENE_QUERY_REFIT;

	sceneDesc.broadPhaseType = physx::PxBroadPhaseType::eSAP; // TODO: Switch to MBP

	m_Scene.reset(m_Physics->createScene(sceneDesc));
	ASSERT_FATAL(m_Scene);

	physx::PxSceneWriteLock scopedLock(*m_Scene);
	m_Scene->setVisualizationParameter(physx::PxVisualizationParameter::eSCALE, 1.f);
	m_Scene->setVisualizationParameter(physx::PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);
	LOG(Info, Physics, "Physics system initialized!");

	physx::PxPvdSceneClient* pvdClient = m_Scene->getScenePvdClient();
	if (pvdClient)
	{
		pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_CONSTRAINTS, true);
		pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_CONTACTS, true);
		pvdClient->setScenePvdFlag(physx::PxPvdSceneFlag::eTRANSMIT_SCENEQUERIES, true);
	}
}

PhysicsEngine::~PhysicsEngine()
{}

void PhysicsEngine::CreateDebuggerConnection()
{
#ifdef _DEBUG
	//The normal way to connect to pvd.  PVD needs to be running at the time this function is called.
	//We don't worry about the return value because we are already registered as a listener for connections
	//and thus our onPvdConnected call will take care of setting up our basic connection state.
	char ip[] = "127.0.0.1";
	m_Transport.reset(physx::PxDefaultPvdSocketTransportCreate(ip, 5425, 1000));
	if (!m_Transport)
	{
		return;
	}

	//Use these flags for a clean profile trace with minimal overhead
	physx::PxPvdInstrumentationFlags flags = physx::PxPvdInstrumentationFlag::eALL;

	m_VisualDebugger.reset(physx::PxCreatePvd(*m_Foundation));
	m_VisualDebugger->connect(*m_Transport, flags);
#endif
}

void PhysicsEngine::Simulate(float deltaTime)
{
	m_TimeAccumulator += deltaTime;
	if (m_TimeAccumulator < PhysicsEngine::TimeStep)
	{
		return;
	}

	m_TimeAccumulator -= PhysicsEngine::TimeStep;
	TEMP_ALLOCATOR_SCOPE;
	uint32_t desiredSize = 1024 * 1024; // 1mb
	size_t sizeWithAlignment = desiredSize + 16 * 1024; // 16 KB align needed
	tmp::unique_array<uint8_t> scratchMemory = tmp::make_unique_array<uint8_t>(sizeWithAlignment);
	{
		physx::PxSceneWriteLock writeLock(*m_Scene);
		void* scratchMemoryAddress = scratchMemory.get();

		m_Scene->simulate(
			PhysicsEngine::TimeStep,
			nullptr,
			std::align(16 * 1024, desiredSize, scratchMemoryAddress, sizeWithAlignment),
			desiredSize);
	}
	m_HasIssuedSimulate = true;
}

inline void SetZmeyTransformFromPhysx(Zmey::Components::TransformInstance& transform, const physx::PxTransform& pxTransform)
{
	transform.Position().x = pxTransform.p.x;
	transform.Position().y = pxTransform.p.y;
	transform.Position().z = pxTransform.p.z;
	transform.Rotation().x = pxTransform.q.x;
	transform.Rotation().y = pxTransform.q.y;
	transform.Rotation().z = pxTransform.q.z;
	transform.Rotation().w = pxTransform.q.w;
}

inline void SetPhysxTransformFromZmey(physx::PxTransform& pxTransform, const Zmey::Components::TransformInstance& transform)
{
	pxTransform.p.x = transform.Position().x;
	pxTransform.p.y = transform.Position().y;
	pxTransform.p.z = transform.Position().z;
	pxTransform.q.x = transform.Rotation().x;
	pxTransform.q.y = transform.Rotation().y;
	pxTransform.q.z = transform.Rotation().z;
	pxTransform.q.w = transform.Rotation().w;
}

void PhysicsEngine::FetchResults()
{
	if (!m_HasIssuedSimulate)
	{
		return;
	}

	{
		physx::PxSceneWriteLock writeLock(*m_Scene);

		physx::PxU32 error(physx::PxErrorCode::eNO_ERROR);
		m_Scene->fetchResults(true, &error);
		ASSERT(error == physx::PxErrorCode::eNO_ERROR);
	}
	m_HasIssuedSimulate = false;

	physx::PxU32 activeTransformsCount = -1;
	auto activeTransforms = m_Scene->getActiveTransforms(activeTransformsCount);
	auto& transformManager = m_World->GetManager<Zmey::Components::TransformManager>();
	for (physx::PxU32 i = 0; i < activeTransformsCount; ++i)
	{
		auto entityId = static_cast<Zmey::EntityId>(reinterpret_cast<uint64_t>(activeTransforms[i].userData));
		auto transform = transformManager.Lookup(entityId);
		// TODO This currently copies transforms as an array of structs; change to SoA.
		SetZmeyTransformFromPhysx(transform, activeTransforms[i].actor2World);
	}
}

PhysicsEngine::GeometryPtr PhysicsEngine::CreateBoxGeometry(float width, float height, float depth) const
{
	physx::PxBoxGeometry box(width / 2, height / 2, depth / 2);
	GeometryPtr result(new physx::PxGeometryHolder(std::move(box)));
	return result;
}
PhysicsEngine::GeometryPtr PhysicsEngine::CreateSphereGeometry(float radius) const
{
	physx::PxSphereGeometry sphere(radius);
	GeometryPtr result(new physx::PxGeometryHolder(std::move(sphere)));
	return result;
}
PhysicsEngine::GeometryPtr PhysicsEngine::CreateCapsuleGeometry(float radius, float height) const
{
	physx::PxCapsuleGeometry capsule(radius, height / 2);
	GeometryPtr result(new physx::PxGeometryHolder(std::move(capsule)));
	return result;
}

stl::unique_ptr<PhysicsActor> PhysicsEngine::CreatePhysicsActor(EntityId entityId, const PhysicsActorDescription& actorDescription)
{
	const CombinedMaterialInfo* material = FindMaterial(actorDescription.Material);
	ASSERT(material);
	physx::PxRigidActor* actor = nullptr;
	auto actorTransform = m_World->GetManager<Zmey::Components::TransformManager>().Lookup(entityId);
	physx::PxTransform currentTransform;
	SetPhysxTransformFromZmey(currentTransform, actorTransform);
	if (actorDescription.IsStatic)
	{
		actor = m_Physics->createRigidStatic(currentTransform);
	}
	else
	{
		actor = m_Physics->createRigidDynamic(currentTransform);
	}
	physx::PxShapeFlags flags = physx::PxShapeFlag::eSIMULATION_SHAPE | physx::PxShapeFlag::eVISUALIZATION |
		static_cast<physx::PxShapeFlag::Enum>(actorDescription.IsTrigger * physx::PxShapeFlag::eTRIGGER_SHAPE) |
		static_cast<physx::PxShapeFlag::Enum>(!actorDescription.IsTrigger * physx::PxShapeFlag::eSCENE_QUERY_SHAPE);
	physx::PxShape* shape = m_Physics->createShape(actorDescription.Geometry->any(), *material->PhysxMaterial, true, flags);
	actor->attachShape(*shape);
	actor->userData = reinterpret_cast<void*>(static_cast<uint64_t>(entityId));
	shape->release();
	m_Scene->addActor(*actor);

	stl::unique_ptr<Zmey::Physics::PhysicsActor> physicsActor(new Zmey::Physics::PhysicsActor(*actor, actorDescription.IsStatic));
	return physicsActor;
}
void PhysicsEngine::CreatePhysicsMaterial(Zmey::Name name, const PhysicsMaterialDescription& description)
{
	auto material = m_Physics->createMaterial(description.Friction, description.Friction, description.Restitution);
	m_Materials.push_back(std::make_pair(name, CombinedMaterialInfo{ material, description }));
}

const PhysicsEngine::CombinedMaterialInfo* PhysicsEngine::FindMaterial(Zmey::Name name) const
{
	auto it = std::find_if(m_Materials.begin(), m_Materials.end(), [name](const std::pair<Zmey::Name, CombinedMaterialInfo>& materialNamePair)
	{
		return materialNamePair.first == name;
	});
	if (it != m_Materials.end())
	{
		return &it->second;
	}
	return nullptr;
}

}

}<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#if !defined(TRU64DEFINITIONS_HEADER_GUARD_1357924680)
#define TRU64DEFINITIONS_HEADER_GUARD_1357924680

// ---------------------------------------------------------------------------
//  A define in the build for each project is also used to control whether
//  the export keyword is from the project's viewpoint or the client's.
//  These defines provide the platform specific keywords that they need
//  to do this.
// ---------------------------------------------------------------------------

#define XALAN_PLATFORM_EXPORT
#define XALAN_PLATFORM_IMPORT
#define XALAN_PLATFORM_EXPORT_FUNCTION(T) T XALAN_PLATFORM_EXPORT
#define XALAN_PLATFORM_IMPORT_FUNCTION(T) T XALAN_PLATFORM_IMPORT

// This next line enables standard IO streams.
#define __USE_STD_IOSTREAM
#define XALAN_RTTI_AVAILABLE
#define XALAN_XALANDOMCHAR_USHORT_MISMATCH
#define XALAN_POSIX2_AVAILABLE
#define XALAN_INLINE_INITIALIZATION
#define XALAN_LSTRSUPPORT

#if defined(__STD_STRICT_ANSI) || defined(__STD_STRICT_ANSI_ERRORS)
#define XALAN_STRICT_ANSI_HEADERS
#define XALAN_SIZE_T_IN_NAMESPACE_STD
#endif

#define XALAN_UNALIGNED __unaligned

#endif  // TRU64DEFINITIONS_HEADER_GUARD_1357924680
<commit_msg>New macro to configure STL.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 1999-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#if !defined(TRU64DEFINITIONS_HEADER_GUARD_1357924680)
#define TRU64DEFINITIONS_HEADER_GUARD_1357924680

// ---------------------------------------------------------------------------
//  A define in the build for each project is also used to control whether
//  the export keyword is from the project's viewpoint or the client's.
//  These defines provide the platform specific keywords that they need
//  to do this.
// ---------------------------------------------------------------------------

#define XALAN_PLATFORM_EXPORT
#define XALAN_PLATFORM_IMPORT
#define XALAN_PLATFORM_EXPORT_FUNCTION(T) T XALAN_PLATFORM_EXPORT
#define XALAN_PLATFORM_IMPORT_FUNCTION(T) T XALAN_PLATFORM_IMPORT

// This next line enables standard IO streams.
#define __USE_STD_IOSTREAM
#define XALAN_RTTI_AVAILABLE
#define XALAN_XALANDOMCHAR_USHORT_MISMATCH
#define XALAN_POSIX2_AVAILABLE
#define XALAN_INLINE_INITIALIZATION
#define XALAN_LSTRSUPPORT
#define XALAN_MODERN_STL

#if defined(__STD_STRICT_ANSI) || defined(__STD_STRICT_ANSI_ERRORS)
#define XALAN_STRICT_ANSI_HEADERS
#define XALAN_SIZE_T_IN_NAMESPACE_STD
#endif

#define XALAN_UNALIGNED __unaligned

#endif  // TRU64DEFINITIONS_HEADER_GUARD_1357924680
<|endoftext|>


<commit_before><commit_msg>punisher - hud tests, menu centering attempt<commit_after><|endoftext|>


<commit_before>//
// bench.cpp : spdlog benchmarks
//
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <atomic>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/file_sinks.h"
#include "spdlog/sinks/stdout_sinks.h"
#include "spdlog/sinks/null_sink.h"
#include "utils.h"

using namespace std;
using namespace std::chrono;
using namespace spdlog;
using namespace spdlog::sinks;
using namespace utils;

void bench(int howmany, std::shared_ptr<spdlog::logger> log)
{
		cout << log->name() << ", " << format(howmany) << " iterations.." << endl;

        auto start = system_clock::now();
        for (auto i = 0; i < howmany; ++i)
        {
            log->info("Hello logger: msg number ") << i;
        }

        auto delta = system_clock::now() - start;
        auto delta_d = duration_cast<duration<double>> (delta).count();
        cout << "Delta:" << format(delta_d) << " seconds" << endl;
        cout << "Rate:" << format(howmany / delta_d) << "/sec" << endl << endl;
}

void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
{

        cout << log->name() << ", " << format(howmany) << " iterations.." << endl;
        std::atomic<int > msg_counter{0};
      	vector<thread> threads;
		auto start = system_clock::now();
		for (int t = 0; t < thread_count; ++t)
		{
		    threads.push_back(std::thread([&]() {
				while(msg_counter++ < howmany)
			        log->info("Hello logger: msg number ") << msg_counter;

			}));
	    }

		for(auto &t:threads)
    	{
    	    t.join();
	    };

        auto delta = system_clock::now() - start;
        auto delta_d = duration_cast<duration<double>> (delta).count();
        cout << "Delta:" << format(delta_d) << " seconds" << endl;
        cout << "Rate:" << format(howmany / delta_d) << "/sec" << endl << endl;
 }

int main(int argc, char* argv[])
{

    try {

		int howmany = argc <= 1 ? 100000 : atoi(argv[1]);
		int threads = argc <= 2 ? 4 : atoi(argv[2]);
		int flush_interval = 100;

		cout << "*******************************************************************************\n";
		cout << "Single threaded benchmarks. flush_interval = " << flush_interval << endl;
		cout << "*******************************************************************************\n";

		auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", 1024 * 1024 * 5, 5, flush_interval);
		bench(howmany, rotating_st);

		auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st", flush_interval);
		bench(howmany, daily_st);

		bench(howmany, spdlog::create<null_sink_st>("null_st"));

		cout << "*******************************************************************************\n";
		cout << "Multi threaded benchmarks (" << threads << " threads), flush_interval = " << flush_interval << endl;
		cout << "*******************************************************************************\n";

		auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", 1024 * 1024 * 5, 5, flush_interval);
		bench_mt(howmany, rotating_mt, threads);

		auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt", flush_interval);
		bench_mt(howmany, daily_mt, threads);

		bench_mt(howmany, spdlog::create<null_sink_mt>("null_mt"), threads);
    }
    catch (std::exception &ex)
    {
        std::cerr << "Error: " << ex.what() << std::endl;
        perror("Last error");
    }
    return 0;
}

<commit_msg>bench<commit_after>//
// bench.cpp : spdlog benchmarks
//
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <atomic>
#include "spdlog/spdlog.h"
#include "spdlog/sinks/file_sinks.h"
#include "spdlog/sinks/stdout_sinks.h"
#include "spdlog/sinks/null_sink.h"
#include "utils.h"

using namespace std;
using namespace std::chrono;
using namespace spdlog;
using namespace spdlog::sinks;
using namespace utils;

void bench(int howmany, std::shared_ptr<spdlog::logger> log)
{
		cout << log->name() << "...\t\t" << flush;
        auto start = system_clock::now();
        for (auto i = 0; i < howmany; ++i)
        {
            log->info("Hello logger: msg number ") << i;
        }

        auto delta = system_clock::now() - start;
        auto delta_d = duration_cast<duration<double>> (delta).count();
        cout << format(int(howmany / delta_d)) << "/sec" << endl;
}

void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count)
{

		cout << log->name() << "...\t\t" << flush;
        std::atomic<int > msg_counter{0};
      	vector<thread> threads;
		auto start = system_clock::now();
		for (int t = 0; t < thread_count; ++t)
		{
		    threads.push_back(std::thread([&]() {
				while(msg_counter++ < howmany)
			        log->info("Hello logger: msg number ") << msg_counter;

			}));
	    }

		for(auto &t:threads)
    	{
    	    t.join();
	    };

        auto delta = system_clock::now() - start;
        auto delta_d = duration_cast<duration<double>> (delta).count();
        cout << format(int(howmany / delta_d)) << "/sec" << endl;
 }

int main(int argc, char* argv[])
{

    try {

		int howmany = argc <= 1 ? 250000 : atoi(argv[1]);
		int threads = argc <= 2 ? 4 : atoi(argv[2]);
		int flush_interval = 100;

		cout << "*******************************************************************************\n";
		cout << "Single thread, " << format(howmany)  << " iterations, flush every " << flush_interval << " lines"<< endl;
		cout << "*******************************************************************************\n";

		auto rotating_st = spdlog::rotating_logger_st("rotating_st", "logs/rotating_st", 1024 * 1024 * 5, 5, flush_interval);
		bench(howmany, rotating_st);

		auto daily_st = spdlog::daily_logger_st("daily_st", "logs/daily_st", flush_interval);
		bench(howmany, daily_st);

		bench(howmany, spdlog::create<null_sink_st>("null_st"));

		cout << "\n*******************************************************************************\n";
		cout << threads << " threads, " << format(howmany)  << " iterations, flush every " << flush_interval << " lines" << endl;
		cout << "*******************************************************************************\n";

		auto rotating_mt = spdlog::rotating_logger_mt("rotating_mt", "logs/rotating_mt", 1024 * 1024 * 5, 5, flush_interval);
		bench_mt(howmany, rotating_mt, threads);

		auto daily_mt = spdlog::daily_logger_mt("daily_mt", "logs/daily_mt", flush_interval);
		bench_mt(howmany, daily_mt, threads);

		bench_mt(howmany, spdlog::create<null_sink_mt>("null_mt"), threads);
    }
    catch (std::exception &ex)
    {
        std::cerr << "Error: " << ex.what() << std::endl;
        perror("Last error");
    }
    return 0;
}

<|endoftext|>


<commit_before>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2019 Ryo Suzuki
//	Copyright (c) 2016-2019 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once
# include <memory>
# include "Fwd.hpp"
# include "AlignedMemory.hpp"

namespace s3d
{
	namespace detail
	{
		class ConstantBufferBase
		{
		private:

			class ConstantBufferDetail;

			std::shared_ptr<ConstantBufferDetail> m_detail;

		public:

			ConstantBufferBase() = default;

			ConstantBufferBase(const ConstantBufferBase&) = default;

			explicit ConstantBufferBase(size_t size);

			bool _internal_update(const void* data, size_t size);

			const ConstantBufferDetail* _detail() const;
		};
	}

	template <class Type>
	class ConstantBuffer
	{
	public:

		static constexpr size_t Size = sizeof(Type);

		static constexpr size_t Alignment = std::max<size_t>(alignof(Type), 16);

	private:

		static_assert(Size <= 16 * 4096); // <= 64KB

		static_assert(Size % 16 == 0);

		detail::ConstantBufferBase m_base;

		Type* const m_data = AlignedMalloc<Type, Alignment>();

		bool m_hasDirty = false;

		bool update()
		{
			return m_base._internal_update(m_data, Size);
		}

	public:

		ConstantBuffer()
			: m_base(Size)
		{

		}

		explicit ConstantBuffer(const Type& data)
			: ConstantBuffer()
		{
			m_hasDirty = true;
			*m_data = data;
		}

		~ConstantBuffer()
		{
			AlignedFree(m_data);
		}

		[[nodiscard]] constexpr size_t getDataSize() const noexcept
		{
			return Size;
		}

		[[nodiscard]] const float* getPtr() const
		{
			return static_cast<const float*>(static_cast<const void*>(m_data));
		}

		[[nodiscard]] Type& get()
		{
			m_hasDirty = true;
			return *m_data;
		}

		[[nodiscard]] const Type& get() const
		{
			return *m_data;
		}

		bool _update_if_dirty()
		{
			if (!m_hasDirty)
			{
				return true;
			}

			return update();
		}

		[[nodiscard]] const detail::ConstantBufferBase& base() const
		{
			return m_base;
		}

		[[nodiscard]] Type& operator *()
		{
			m_hasDirty = true;
			return *m_data;
		}

		[[nodiscard]] const Type& operator *() const
		{
			return *m_data;
		}

		[[nodiscard]] Type* operator ->()
		{
			m_hasDirty = true;
			return m_data;
		}

		[[nodiscard]] const Type* operator ->() const
		{
			return *m_data;
		}
	};
}
<commit_msg>add header<commit_after>//-----------------------------------------------
//
//	This file is part of the Siv3D Engine.
//
//	Copyright (c) 2008-2019 Ryo Suzuki
//	Copyright (c) 2016-2019 OpenSiv3D Project
//
//	Licensed under the MIT License.
//
//-----------------------------------------------

# pragma once
# include <memory>
# include <algorithm>
# include "Fwd.hpp"
# include "AlignedMemory.hpp"

namespace s3d
{
	namespace detail
	{
		class ConstantBufferBase
		{
		private:

			class ConstantBufferDetail;

			std::shared_ptr<ConstantBufferDetail> m_detail;

		public:

			ConstantBufferBase() = default;

			ConstantBufferBase(const ConstantBufferBase&) = default;

			explicit ConstantBufferBase(size_t size);

			bool _internal_update(const void* data, size_t size);

			const ConstantBufferDetail* _detail() const;
		};
	}

	template <class Type>
	class ConstantBuffer
	{
	public:

		static constexpr size_t Size = sizeof(Type);

		static constexpr size_t Alignment = std::max<size_t>(alignof(Type), 16);

	private:

		static_assert(Size <= 16 * 4096); // <= 64KB

		static_assert(Size % 16 == 0);

		detail::ConstantBufferBase m_base;

		Type* const m_data = AlignedMalloc<Type, Alignment>();

		bool m_hasDirty = false;

		bool update()
		{
			return m_base._internal_update(m_data, Size);
		}

	public:

		ConstantBuffer()
			: m_base(Size)
		{

		}

		explicit ConstantBuffer(const Type& data)
			: ConstantBuffer()
		{
			m_hasDirty = true;
			*m_data = data;
		}

		~ConstantBuffer()
		{
			AlignedFree(m_data);
		}

		[[nodiscard]] constexpr size_t getDataSize() const noexcept
		{
			return Size;
		}

		[[nodiscard]] const float* getPtr() const
		{
			return static_cast<const float*>(static_cast<const void*>(m_data));
		}

		[[nodiscard]] Type& get()
		{
			m_hasDirty = true;
			return *m_data;
		}

		[[nodiscard]] const Type& get() const
		{
			return *m_data;
		}

		bool _update_if_dirty()
		{
			if (!m_hasDirty)
			{
				return true;
			}

			return update();
		}

		[[nodiscard]] const detail::ConstantBufferBase& base() const
		{
			return m_base;
		}

		[[nodiscard]] Type& operator *()
		{
			m_hasDirty = true;
			return *m_data;
		}

		[[nodiscard]] const Type& operator *() const
		{
			return *m_data;
		}

		[[nodiscard]] Type* operator ->()
		{
			m_hasDirty = true;
			return m_data;
		}

		[[nodiscard]] const Type* operator ->() const
		{
			return *m_data;
		}
	};
}
<|endoftext|>


<commit_before>#pragma once

#include <agency/detail/config.hpp>
#include <agency/execution_policy.hpp>
#include <agency/flattened_executor.hpp>
#include <agency/cuda/execution_agent.hpp>
#include <agency/cuda/grid_executor.hpp>
#include <agency/cuda/parallel_executor.hpp>
#include <agency/cuda/concurrent_executor.hpp>
#include <agency/cuda/nested_executor.hpp>
#include <agency/cuda/bulk_invoke.hpp>
#include <agency/detail/tuple.hpp>
#include <type_traits>

namespace agency
{
namespace cuda
{
namespace detail
{

// add basic_execution_policy to allow us to catch its derivations as overloads of bulk_invoke, etc.
template<class ExecutionAgent,
         class BulkExecutor,
         class ExecutionCategory = typename execution_agent_traits<ExecutionAgent>::execution_category,
         class DerivedExecutionPolicy = void>
class basic_execution_policy :
  public agency::detail::basic_execution_policy<
    ExecutionAgent,
    BulkExecutor,
    ExecutionCategory,
    typename std::conditional<
      std::is_void<DerivedExecutionPolicy>::value,
      basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
      DerivedExecutionPolicy
    >::type
>
{
  public:
    // inherit the base class's constructors
    using agency::detail::basic_execution_policy<
      ExecutionAgent,
      BulkExecutor,
      ExecutionCategory,
      typename std::conditional<
        std::is_void<DerivedExecutionPolicy>::value,
        basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
        DerivedExecutionPolicy
      >::type
    >::basic_execution_policy;
}; // end basic_execution_policy

} // end detail

class parallel_execution_policy : public detail::basic_execution_policy<cuda::parallel_agent, cuda::parallel_executor, parallel_execution_tag, parallel_execution_policy>
{
  private:
    using super_t = detail::basic_execution_policy<cuda::parallel_agent, cuda::parallel_executor, parallel_execution_tag, parallel_execution_policy>;

    using par2d_t = detail::basic_execution_policy<cuda::parallel_agent_2d, cuda::parallel_executor, parallel_execution_tag>;

  public:
    using super_t::basic_execution_policy;

    using super_t::operator();

    // XXX consider whether we really want this functionality a member of parallel_execution_policy
    inline par2d_t operator()(agency::size2 shape) const
    {
      par2d_t par2d;

      return par2d(shape);
    }

    // XXX consider whether we really want this functionality a member of parallel_execution_policy
    template<class ExecutionPolicy>
    agency::detail::nested_execution_policy<
      par2d_t,
      agency::detail::decay_t<ExecutionPolicy>
    >
      operator()(agency::size2 domain, ExecutionPolicy&& exec) const
    {
      par2d_t par2d;

      return par2d(domain, std::forward<ExecutionPolicy>(exec));
    }
};

const parallel_execution_policy par{};

class concurrent_execution_policy : public detail::basic_execution_policy<cuda::concurrent_agent, cuda::concurrent_executor, concurrent_execution_tag, concurrent_execution_policy>
{
  private:
    using super_t = detail::basic_execution_policy<cuda::concurrent_agent, cuda::concurrent_executor, concurrent_execution_tag, concurrent_execution_policy>;

    using con2d_t = detail::basic_execution_policy<cuda::concurrent_agent_2d, cuda::concurrent_executor, concurrent_execution_tag>;

  public:
    using super_t::basic_execution_policy;

    using super_t::operator();

    // XXX consider whether we really want this functionality a member of concurrent_execution_policy
    inline con2d_t operator()(agency::size2 shape) const
    {
      con2d_t con2d;

      return con2d(shape);
    }

    // XXX consider whether we really want this functionality a member of concurrent_execution_policy
    template<class ExecutionPolicy>
    agency::detail::nested_execution_policy<
      con2d_t,
      agency::detail::decay_t<ExecutionPolicy>
    >
      operator()(agency::size2 domain, ExecutionPolicy&& exec) const
    {
      con2d_t con2d;

      return con2d(domain, std::forward<ExecutionPolicy>(exec));
    }
};

const concurrent_execution_policy con{};

namespace detail
{

// specialize rebind_executor for cuda's executor types
template<class ExecutionPolicy, class Enable = void>
struct rebind_executor_impl;

template<class ExecutionPolicy>
struct rebind_executor_impl<
  ExecutionPolicy,
  typename std::enable_if<
    std::is_same<
      typename ExecutionPolicy::execution_category,
      parallel_execution_tag
    >::value
  >::type
>
{
  using type = cuda::parallel_execution_policy;
};

// specialize rebind_executor for cuda::concurrent_executor
template<class ExecutionPolicy>
struct rebind_executor_impl<
  ExecutionPolicy,
  typename std::enable_if<
    std::is_same<
      typename ExecutionPolicy::execution_category,
      concurrent_execution_tag
    >::value
  >::type
>
{
  using type = cuda::concurrent_execution_policy;
};

} // end detail
} // end cuda

// specialize is_execution_policy
template<class ExecutionAgent,
         class BulkExecutor,
         class ExecutionCategory,
         class DerivedExecutionPolicy>
struct is_execution_policy<cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>> : std::true_type {};

template<>
struct is_execution_policy<cuda::parallel_execution_policy> : std::true_type {};

template<>
struct is_execution_policy<cuda::concurrent_execution_policy> : std::true_type {};

template<class ExecutionPolicy>
struct rebind_executor<ExecutionPolicy, cuda::grid_executor>
{
  using type = typename cuda::detail::rebind_executor_impl<ExecutionPolicy>::type;
};

template<class ExecutionPolicy>
struct rebind_executor<ExecutionPolicy, cuda::concurrent_executor>
{
  using type = typename cuda::detail::rebind_executor_impl<ExecutionPolicy>::type;
};

} // end agency

<commit_msg>Make a note on the rebind_executor specialization for grid_executor<commit_after>#pragma once

#include <agency/detail/config.hpp>
#include <agency/execution_policy.hpp>
#include <agency/flattened_executor.hpp>
#include <agency/cuda/execution_agent.hpp>
#include <agency/cuda/grid_executor.hpp>
#include <agency/cuda/parallel_executor.hpp>
#include <agency/cuda/concurrent_executor.hpp>
#include <agency/cuda/nested_executor.hpp>
#include <agency/cuda/bulk_invoke.hpp>
#include <agency/detail/tuple.hpp>
#include <type_traits>

namespace agency
{
namespace cuda
{
namespace detail
{

// add basic_execution_policy to allow us to catch its derivations as overloads of bulk_invoke, etc.
template<class ExecutionAgent,
         class BulkExecutor,
         class ExecutionCategory = typename execution_agent_traits<ExecutionAgent>::execution_category,
         class DerivedExecutionPolicy = void>
class basic_execution_policy :
  public agency::detail::basic_execution_policy<
    ExecutionAgent,
    BulkExecutor,
    ExecutionCategory,
    typename std::conditional<
      std::is_void<DerivedExecutionPolicy>::value,
      basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
      DerivedExecutionPolicy
    >::type
>
{
  public:
    // inherit the base class's constructors
    using agency::detail::basic_execution_policy<
      ExecutionAgent,
      BulkExecutor,
      ExecutionCategory,
      typename std::conditional<
        std::is_void<DerivedExecutionPolicy>::value,
        basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>,
        DerivedExecutionPolicy
      >::type
    >::basic_execution_policy;
}; // end basic_execution_policy

} // end detail

class parallel_execution_policy : public detail::basic_execution_policy<cuda::parallel_agent, cuda::parallel_executor, parallel_execution_tag, parallel_execution_policy>
{
  private:
    using super_t = detail::basic_execution_policy<cuda::parallel_agent, cuda::parallel_executor, parallel_execution_tag, parallel_execution_policy>;

    using par2d_t = detail::basic_execution_policy<cuda::parallel_agent_2d, cuda::parallel_executor, parallel_execution_tag>;

  public:
    using super_t::basic_execution_policy;

    using super_t::operator();

    // XXX consider whether we really want this functionality a member of parallel_execution_policy
    inline par2d_t operator()(agency::size2 shape) const
    {
      par2d_t par2d;

      return par2d(shape);
    }

    // XXX consider whether we really want this functionality a member of parallel_execution_policy
    template<class ExecutionPolicy>
    agency::detail::nested_execution_policy<
      par2d_t,
      agency::detail::decay_t<ExecutionPolicy>
    >
      operator()(agency::size2 domain, ExecutionPolicy&& exec) const
    {
      par2d_t par2d;

      return par2d(domain, std::forward<ExecutionPolicy>(exec));
    }
};

const parallel_execution_policy par{};

class concurrent_execution_policy : public detail::basic_execution_policy<cuda::concurrent_agent, cuda::concurrent_executor, concurrent_execution_tag, concurrent_execution_policy>
{
  private:
    using super_t = detail::basic_execution_policy<cuda::concurrent_agent, cuda::concurrent_executor, concurrent_execution_tag, concurrent_execution_policy>;

    using con2d_t = detail::basic_execution_policy<cuda::concurrent_agent_2d, cuda::concurrent_executor, concurrent_execution_tag>;

  public:
    using super_t::basic_execution_policy;

    using super_t::operator();

    // XXX consider whether we really want this functionality a member of concurrent_execution_policy
    inline con2d_t operator()(agency::size2 shape) const
    {
      con2d_t con2d;

      return con2d(shape);
    }

    // XXX consider whether we really want this functionality a member of concurrent_execution_policy
    template<class ExecutionPolicy>
    agency::detail::nested_execution_policy<
      con2d_t,
      agency::detail::decay_t<ExecutionPolicy>
    >
      operator()(agency::size2 domain, ExecutionPolicy&& exec) const
    {
      con2d_t con2d;

      return con2d(domain, std::forward<ExecutionPolicy>(exec));
    }
};

const concurrent_execution_policy con{};

namespace detail
{

// specialize rebind_executor for cuda's executor types
template<class ExecutionPolicy, class Enable = void>
struct rebind_executor_impl;

template<class ExecutionPolicy>
struct rebind_executor_impl<
  ExecutionPolicy,
  typename std::enable_if<
    std::is_same<
      typename ExecutionPolicy::execution_category,
      parallel_execution_tag
    >::value
  >::type
>
{
  using type = cuda::parallel_execution_policy;
};

// specialize rebind_executor for cuda::concurrent_executor
template<class ExecutionPolicy>
struct rebind_executor_impl<
  ExecutionPolicy,
  typename std::enable_if<
    std::is_same<
      typename ExecutionPolicy::execution_category,
      concurrent_execution_tag
    >::value
  >::type
>
{
  using type = cuda::concurrent_execution_policy;
};

} // end detail
} // end cuda

// specialize is_execution_policy
template<class ExecutionAgent,
         class BulkExecutor,
         class ExecutionCategory,
         class DerivedExecutionPolicy>
struct is_execution_policy<cuda::detail::basic_execution_policy<ExecutionAgent,BulkExecutor,ExecutionCategory,DerivedExecutionPolicy>> : std::true_type {};

template<>
struct is_execution_policy<cuda::parallel_execution_policy> : std::true_type {};

template<>
struct is_execution_policy<cuda::concurrent_execution_policy> : std::true_type {};

template<class ExecutionPolicy>
struct rebind_executor<ExecutionPolicy, cuda::grid_executor>
{
  // this rebind makes sense because cuda::parallel_execution_policy
  // has a constructor that takes cuda::grid_executor
  using type = cuda::parallel_execution_policy;
};

template<class ExecutionPolicy>
struct rebind_executor<ExecutionPolicy, cuda::concurrent_executor>
{
  using type = typename cuda::detail::rebind_executor_impl<ExecutionPolicy>::type;
};

} // end agency

<|endoftext|>


<commit_before>/**
 * @file llviewereventrecorder.cpp
 * @brief Viewer event recording and playback support for mouse and keyboard events
 *
 * $LicenseInfo:firstyear=2013&license=viewerlgpl$
 *
 * Copyright (c) 2013, Linden Research, Inc.
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewereventrecorder.h"
#include "llui.h"
#include "llleap.h"

LLViewerEventRecorder::LLViewerEventRecorder() {

  clear(UNDEFINED);
  logEvents = false;
  // Remove any previous event log file
  std::string old_log_ui_events_to_llsd_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.old");
  LLFile::remove(old_log_ui_events_to_llsd_file);

  mLogFilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.llsd");
  LLFile::rename(mLogFilename, old_log_ui_events_to_llsd_file);

  setEventLoggingOff(); // <FS:ND/> Initialize ... otherwise it's random if on or off.
}

bool LLViewerEventRecorder::displayViewerEventRecorderMenuItems() {
  return LLUI::sSettingGroups["config"]->getBOOL("ShowEventRecorderMenuItems");
}

void LLViewerEventRecorder::setEventLoggingOn() {
  if (! mLog.is_open()) {
    mLog.open(mLogFilename, llofstream::out);
  }
  logEvents=true;
  lldebugs << "LLViewerEventRecorder::setEventLoggingOn event logging turned on" << llendl;
}

void LLViewerEventRecorder::setEventLoggingOff() {
  logEvents=false;
  mLog.flush();
  mLog.close();
  lldebugs << "LLViewerEventRecorder::setEventLoggingOff event logging turned off" << llendl;
}

 LLViewerEventRecorder::~LLViewerEventRecorder() {
  if (mLog.is_open()) {
      mLog.close();
    }
}

void LLViewerEventRecorder::clear_xui() {
  xui.clear();
}

void LLViewerEventRecorder::clear(S32 r) {

  xui.clear();

  local_x=r;
  local_y=r;

  global_x=r;
  global_y=r;

}

void LLViewerEventRecorder::setMouseLocalCoords(S32 x, S32 y) {
  local_x=x;
  local_y=y;
}

void LLViewerEventRecorder::setMouseGlobalCoords(S32 x, S32 y) {
  global_x=x;
  global_y=y;
}

void LLViewerEventRecorder::updateMouseEventInfo(S32 local_x, S32 local_y, S32 global_x, S32 global_y, std::string mName) {
  if (! logEvents) return; //<FS:ND/> Do nothing if off

  LLView * target_view = LLUI::resolvePath(LLUI::getRootView(), xui);
  if (! target_view) {
    lldebugs << "LLViewerEventRecorder::updateMouseEventInfo - xui path on file at moment is NOT valid - so DO NOT record these local coords" << llendl;
    return;
  }
  lldebugs << "LLViewerEventRecorder::updateMouseEventInfo b4 updatemouseeventinfo - local_x|global x   "<< this->local_x << " " << this->global_x  << "local/global y " << this->local_y << " " << this->global_y << " mname: " << mName << " xui: " << xui << llendl;

  if (this->local_x < 1 && this->local_y<1 && local_x && local_y) {
    this->local_x=local_x;
    this->local_y=local_y;
  }
  this->global_x=global_x;
  this->global_y=global_y;

  // ONLY record deepest xui path for hierarchy searches - or first/only xui for floaters/panels reached via mouse captor - and llmousehandler
  if (mName!="" &&  mName!="/" && xui=="") {
    //	xui=std::string("/")+mName+xui;
    //xui=mName+xui;
    xui = mName; // TODO review confirm we never call with partial path - also cAN REMOVE CHECK FOR "" - ON OTHER HAND IT'S PRETTY HARMLESS
  }

  lldebugs << "LLViewerEventRecorder::updateMouseEventInfo after updatemouseeventinfo - local_x|global x   "<< this->local_x << " " << this->global_x  << "local/global y " << this->local_y << " " << this->global_y << " mname: " << mName << " xui: " << xui << llendl;
}

void LLViewerEventRecorder::logVisibilityChange(std::string xui, std::string name, BOOL visibility, std::string event_subtype) {
  if (! logEvents) return; //<FS:ND/> Do nothing if off

  LLSD  event=LLSD::emptyMap();

  event.insert("event",LLSD(std::string("visibility")));

  if (visibility) {
    event.insert("visibility",LLSD(true));
  } else {
    event.insert("visibility",LLSD(false));
  }

  if (event_subtype!="") {
    event.insert("event_subtype", LLSD(event_subtype));
  }

  if(name!="") {
    event.insert("name",LLSD(name));
  }

  if (xui!="") {
    event.insert("path",LLSD(xui));
  }

  event.insert("timestamp",LLSD(LLDate::now().asString()));
  recordEvent(event);
}

std::string LLViewerEventRecorder::get_xui() {
  return xui;
}
void LLViewerEventRecorder::update_xui(std::string xui) {
  if (xui!="" && this->xui=="" ) {
    lldebugs << "LLViewerEventRecorder::update_xui to " << xui << llendl;
    this->xui=xui;
  } else {
    lldebugs << "LLViewerEventRecorder::update_xui called with empty string" << llendl;
  }
}

void LLViewerEventRecorder::logKeyEvent(KEY key, MASK mask) {

  if (! logEvents) return; //<FS:ND/> Do nothing if off
  // NOTE: Event recording only logs keydown events - the viewer itself hides keyup events at a fairly low level in the code and does not appear to care about them anywhere

  LLSD event = LLSD::emptyMap();

  event.insert("event",LLSD("type"));

  // keysym ...or
  // keycode...or
  // char
  event.insert("keysym",LLSD(LLKeyboard::stringFromKey(key)));

  // path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps
  // as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might
  // break the test script and it would be useful to have more context to make these sorts of edits safer

  // TODO  replace this with a call which extracts to an array of names of masks (just like vita expects during playback)
  // This is looking more and more like an object is a good idea, for this part a handy method call to setMask(mask) would be nice :-)
  // call the func - llkeyboard::llsdStringarrayFromMask

  LLSD key_mask=LLSD::emptyArray();

  if (mask & MASK_CONTROL)     { key_mask.append(LLSD("CTL")); }  // Mac command key - has code of 0x1  in llcommon/indra_contstants
  if (mask & MASK_ALT)         { key_mask.append(LLSD("ALT")); }
  if (mask & MASK_SHIFT)       { key_mask.append(LLSD("SHIFT")); }
  if (mask & MASK_MAC_CONTROL) { key_mask.append(LLSD("MAC_CONTROL")); }

  event.insert("mask",key_mask);
  event.insert("timestamp",LLSD(LLDate::now().asString()));

  // Although vita has keyDown and keyUp requests it does not have type as a high-level concept
  // (maybe it should) - instead it has a convenience method that generates the keydown and keyup events
  // Here  we will use  "type" as  our event type

  lldebugs << "LLVIewerEventRecorder::logKeyEvent Serialized LLSD for event " << event.asString() << "\n" << llendl;

  //lldebugs  << "[VITA] key_name: "  << LLKeyboard::stringFromKey(key) << "mask: "<< mask  << "handled by " << getName() << llendl;
  lldebugs  << "LLVIewerEventRecorder::logKeyEvent  key_name: "  << LLKeyboard::stringFromKey(key) << "mask: "<< mask  << llendl;

  recordEvent(event);

}

void LLViewerEventRecorder::playbackRecording() {

  LLSD LeapCommand;

  // ivita sets this on startup, it also sends commands to the viewer to make start, stop, and playback menu items visible in viewer
  LeapCommand =LLUI::sSettingGroups["config"]->getLLSD("LeapPlaybackEventsCommand");

  lldebugs << "[VITA] launching playback - leap command is: " << LLSDXMLStreamer(LeapCommand) << llendl;
  LLLeap::create("", LeapCommand, false); // exception=false

}

void LLViewerEventRecorder::recordEvent(LLSD event) {
  lldebugs << "LLViewerEventRecorder::recordEvent event written to log: " << LLSDXMLStreamer(event) << llendl;
  mLog << event << std::endl;

}
void LLViewerEventRecorder::logKeyUnicodeEvent(llwchar uni_char) {
  if (! logEvents) return;

  // Note: keyUp is not captured since the viewer seems to not care about keyUp events

  LLSD event=LLSD::emptyMap();

  event.insert("timestamp",LLSD(LLDate::now().asString()));

  // keysym ...or
  // keycode...or
  // char

  lldebugs << "Wrapped in conversion to wstring " <<  wstring_to_utf8str(LLWString( 1, uni_char)) << "\n" << llendl;

  event.insert("char",
	       LLSD(  wstring_to_utf8str(LLWString( 1,uni_char))  )
	       );

  // path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps
  // as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might
  // break the test script and it would be useful to have more context to make these sorts of edits safer

  // TODO need to consider mask keys too? Doesn't seem possible - at least not easily at this point

  event.insert("event",LLSD("keyDown"));

  lldebugs  << "[VITA] unicode key: " << uni_char   << llendl;
  lldebugs  << "[VITA] dumpxml " << LLSDXMLStreamer(event) << "\n" << llendl;

  recordEvent(event);

}

void LLViewerEventRecorder::logMouseEvent(std::string button_state,std::string button_name)
{
  if (! logEvents) return;

  LLSD  event=LLSD::emptyMap();

  event.insert("event",LLSD(std::string("mouse"+ button_state)));
  event.insert("button",LLSD(button_name));
  if (xui!="") {
    event.insert("path",LLSD(xui));
  }

  if (local_x>0 && local_y>0) {
    event.insert("local_x",LLSD(local_x));
    event.insert("local_y",LLSD(local_y));
  }

  if (global_x>0 && global_y>0) {
    event.insert("global_x",LLSD(global_x));
    event.insert("global_y",LLSD(global_y));
  }
  event.insert("timestamp",LLSD(LLDate::now().asString()));
  recordEvent(event);

  clear(UNDEFINED);

}
<commit_msg>Remove setEventLoggingOff call in LLViewerEventRecorder now that logEvents is properly initialized<commit_after>/**
 * @file llviewereventrecorder.cpp
 * @brief Viewer event recording and playback support for mouse and keyboard events
 *
 * $LicenseInfo:firstyear=2013&license=viewerlgpl$
 *
 * Copyright (c) 2013, Linden Research, Inc.
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "llviewereventrecorder.h"
#include "llui.h"
#include "llleap.h"

LLViewerEventRecorder::LLViewerEventRecorder() {

  clear(UNDEFINED);
  logEvents = false;
  // Remove any previous event log file
  std::string old_log_ui_events_to_llsd_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.old");
  LLFile::remove(old_log_ui_events_to_llsd_file);

  mLogFilename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife_Events_log.llsd");
  LLFile::rename(mLogFilename, old_log_ui_events_to_llsd_file);
}

bool LLViewerEventRecorder::displayViewerEventRecorderMenuItems() {
  return LLUI::sSettingGroups["config"]->getBOOL("ShowEventRecorderMenuItems");
}

void LLViewerEventRecorder::setEventLoggingOn() {
  if (! mLog.is_open()) {
    mLog.open(mLogFilename, llofstream::out);
  }
  logEvents=true;
  lldebugs << "LLViewerEventRecorder::setEventLoggingOn event logging turned on" << llendl;
}

void LLViewerEventRecorder::setEventLoggingOff() {
  logEvents=false;
  mLog.flush();
  mLog.close();
  lldebugs << "LLViewerEventRecorder::setEventLoggingOff event logging turned off" << llendl;
}

 LLViewerEventRecorder::~LLViewerEventRecorder() {
  if (mLog.is_open()) {
      mLog.close();
    }
}

void LLViewerEventRecorder::clear_xui() {
  xui.clear();
}

void LLViewerEventRecorder::clear(S32 r) {

  xui.clear();

  local_x=r;
  local_y=r;

  global_x=r;
  global_y=r;

}

void LLViewerEventRecorder::setMouseLocalCoords(S32 x, S32 y) {
  local_x=x;
  local_y=y;
}

void LLViewerEventRecorder::setMouseGlobalCoords(S32 x, S32 y) {
  global_x=x;
  global_y=y;
}

void LLViewerEventRecorder::updateMouseEventInfo(S32 local_x, S32 local_y, S32 global_x, S32 global_y, std::string mName) {
  if (! logEvents) return; //<FS:ND/> Do nothing if off

  LLView * target_view = LLUI::resolvePath(LLUI::getRootView(), xui);
  if (! target_view) {
    lldebugs << "LLViewerEventRecorder::updateMouseEventInfo - xui path on file at moment is NOT valid - so DO NOT record these local coords" << llendl;
    return;
  }
  lldebugs << "LLViewerEventRecorder::updateMouseEventInfo b4 updatemouseeventinfo - local_x|global x   "<< this->local_x << " " << this->global_x  << "local/global y " << this->local_y << " " << this->global_y << " mname: " << mName << " xui: " << xui << llendl;

  if (this->local_x < 1 && this->local_y<1 && local_x && local_y) {
    this->local_x=local_x;
    this->local_y=local_y;
  }
  this->global_x=global_x;
  this->global_y=global_y;

  // ONLY record deepest xui path for hierarchy searches - or first/only xui for floaters/panels reached via mouse captor - and llmousehandler
  if (mName!="" &&  mName!="/" && xui=="") {
    //	xui=std::string("/")+mName+xui;
    //xui=mName+xui;
    xui = mName; // TODO review confirm we never call with partial path - also cAN REMOVE CHECK FOR "" - ON OTHER HAND IT'S PRETTY HARMLESS
  }

  lldebugs << "LLViewerEventRecorder::updateMouseEventInfo after updatemouseeventinfo - local_x|global x   "<< this->local_x << " " << this->global_x  << "local/global y " << this->local_y << " " << this->global_y << " mname: " << mName << " xui: " << xui << llendl;
}

void LLViewerEventRecorder::logVisibilityChange(std::string xui, std::string name, BOOL visibility, std::string event_subtype) {
  if (! logEvents) return; //<FS:ND/> Do nothing if off

  LLSD  event=LLSD::emptyMap();

  event.insert("event",LLSD(std::string("visibility")));

  if (visibility) {
    event.insert("visibility",LLSD(true));
  } else {
    event.insert("visibility",LLSD(false));
  }

  if (event_subtype!="") {
    event.insert("event_subtype", LLSD(event_subtype));
  }

  if(name!="") {
    event.insert("name",LLSD(name));
  }

  if (xui!="") {
    event.insert("path",LLSD(xui));
  }

  event.insert("timestamp",LLSD(LLDate::now().asString()));
  recordEvent(event);
}

std::string LLViewerEventRecorder::get_xui() {
  return xui;
}
void LLViewerEventRecorder::update_xui(std::string xui) {
  if (xui!="" && this->xui=="" ) {
    lldebugs << "LLViewerEventRecorder::update_xui to " << xui << llendl;
    this->xui=xui;
  } else {
    lldebugs << "LLViewerEventRecorder::update_xui called with empty string" << llendl;
  }
}

void LLViewerEventRecorder::logKeyEvent(KEY key, MASK mask) {

  if (! logEvents) return; //<FS:ND/> Do nothing if off
  // NOTE: Event recording only logs keydown events - the viewer itself hides keyup events at a fairly low level in the code and does not appear to care about them anywhere

  LLSD event = LLSD::emptyMap();

  event.insert("event",LLSD("type"));

  // keysym ...or
  // keycode...or
  // char
  event.insert("keysym",LLSD(LLKeyboard::stringFromKey(key)));

  // path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps
  // as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might
  // break the test script and it would be useful to have more context to make these sorts of edits safer

  // TODO  replace this with a call which extracts to an array of names of masks (just like vita expects during playback)
  // This is looking more and more like an object is a good idea, for this part a handy method call to setMask(mask) would be nice :-)
  // call the func - llkeyboard::llsdStringarrayFromMask

  LLSD key_mask=LLSD::emptyArray();

  if (mask & MASK_CONTROL)     { key_mask.append(LLSD("CTL")); }  // Mac command key - has code of 0x1  in llcommon/indra_contstants
  if (mask & MASK_ALT)         { key_mask.append(LLSD("ALT")); }
  if (mask & MASK_SHIFT)       { key_mask.append(LLSD("SHIFT")); }
  if (mask & MASK_MAC_CONTROL) { key_mask.append(LLSD("MAC_CONTROL")); }

  event.insert("mask",key_mask);
  event.insert("timestamp",LLSD(LLDate::now().asString()));

  // Although vita has keyDown and keyUp requests it does not have type as a high-level concept
  // (maybe it should) - instead it has a convenience method that generates the keydown and keyup events
  // Here  we will use  "type" as  our event type

  lldebugs << "LLVIewerEventRecorder::logKeyEvent Serialized LLSD for event " << event.asString() << "\n" << llendl;

  //lldebugs  << "[VITA] key_name: "  << LLKeyboard::stringFromKey(key) << "mask: "<< mask  << "handled by " << getName() << llendl;
  lldebugs  << "LLVIewerEventRecorder::logKeyEvent  key_name: "  << LLKeyboard::stringFromKey(key) << "mask: "<< mask  << llendl;

  recordEvent(event);

}

void LLViewerEventRecorder::playbackRecording() {

  LLSD LeapCommand;

  // ivita sets this on startup, it also sends commands to the viewer to make start, stop, and playback menu items visible in viewer
  LeapCommand =LLUI::sSettingGroups["config"]->getLLSD("LeapPlaybackEventsCommand");

  lldebugs << "[VITA] launching playback - leap command is: " << LLSDXMLStreamer(LeapCommand) << llendl;
  LLLeap::create("", LeapCommand, false); // exception=false

}

void LLViewerEventRecorder::recordEvent(LLSD event) {
  lldebugs << "LLViewerEventRecorder::recordEvent event written to log: " << LLSDXMLStreamer(event) << llendl;
  mLog << event << std::endl;

}
void LLViewerEventRecorder::logKeyUnicodeEvent(llwchar uni_char) {
  if (! logEvents) return;

  // Note: keyUp is not captured since the viewer seems to not care about keyUp events

  LLSD event=LLSD::emptyMap();

  event.insert("timestamp",LLSD(LLDate::now().asString()));

  // keysym ...or
  // keycode...or
  // char

  lldebugs << "Wrapped in conversion to wstring " <<  wstring_to_utf8str(LLWString( 1, uni_char)) << "\n" << llendl;

  event.insert("char",
	       LLSD(  wstring_to_utf8str(LLWString( 1,uni_char))  )
	       );

  // path (optional) - for now we are not recording path for key events during record - should not be needed for full record and playback of recorded steps
  // as a vita script - it does become useful if you edit the resulting vita script and wish to remove some steps leading to a key event - that sort of edit might
  // break the test script and it would be useful to have more context to make these sorts of edits safer

  // TODO need to consider mask keys too? Doesn't seem possible - at least not easily at this point

  event.insert("event",LLSD("keyDown"));

  lldebugs  << "[VITA] unicode key: " << uni_char   << llendl;
  lldebugs  << "[VITA] dumpxml " << LLSDXMLStreamer(event) << "\n" << llendl;

  recordEvent(event);

}

void LLViewerEventRecorder::logMouseEvent(std::string button_state,std::string button_name)
{
  if (! logEvents) return;

  LLSD  event=LLSD::emptyMap();

  event.insert("event",LLSD(std::string("mouse"+ button_state)));
  event.insert("button",LLSD(button_name));
  if (xui!="") {
    event.insert("path",LLSD(xui));
  }

  if (local_x>0 && local_y>0) {
    event.insert("local_x",LLSD(local_x));
    event.insert("local_y",LLSD(local_y));
  }

  if (global_x>0 && global_y>0) {
    event.insert("global_x",LLSD(global_x));
    event.insert("global_y",LLSD(global_y));
  }
  event.insert("timestamp",LLSD(LLDate::now().asString()));
  recordEvent(event);

  clear(UNDEFINED);

}
<|endoftext|>


<commit_before><commit_msg>[gtk2] clang warning<commit_after><|endoftext|>


<commit_before>/* The Next Great Finite Element Library. */
/* Copyright (C) 2003  Benjamin S. Kirk */

/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/* Lesser General Public License for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "getpot.h"

#include "laplace_system.h"

#include "boundary_info.h"
#include "dof_map.h"
#include "fe_base.h"
#include "fe_interface.h"
#include "fem_context.h"
#include "mesh.h"
#include "quadrature.h"
#include "string_to_enum.h"

// Bring in everything from the libMesh namespace
using namespace libMesh;

LaplaceSystem::LaplaceSystem( EquationSystems& es,
			      const std::string& name,
			      const unsigned int number)
  : FEMSystem(es, name, number)
{
  return;
}

void LaplaceSystem::init_data ()
{
  // Check the input file for Reynolds number, application type,
  // approximation type
  GetPot infile("laplace.in");

  // Add the solution variable
  u_var = this->add_variable ("u", SECOND, LAGRANGE_VEC);

  this->time_evolving(u_var);

  // Useful debugging options
  // Set verify_analytic_jacobians to 1e-6 to use
  this->verify_analytic_jacobians = infile("verify_analytic_jacobians", 0.);
  this->print_jacobians = infile("print_jacobians", false);
  this->print_element_jacobians = infile("print_element_jacobians", false);

  this->init_dirichlet_bcs();

  // Do the parent's initialization after variables and boundary constraints are defined
  FEMSystem::init_data();
}

void LaplaceSystem::init_dirichlet_bcs()
{
  const boundary_id_type all_ids[6] = {0,1,2,3,4,5};
  std::set<boundary_id_type> boundary_ids( all_ids, all_ids+6 );

  std::vector<unsigned int> vars;
  vars.push_back( u_var );

  BoundaryFunction func( u_var );

  this->get_dof_map().add_dirichlet_boundary( libMesh::DirichletBoundary( boundary_ids, vars, &func ) );
  return;
}

void LaplaceSystem::init_context(DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* fe;
  c.get_element_fe<RealGradient>( u_var, fe );

  // We should prerequest all the data
  // we will need to build the linear system.
  fe->get_JxW();
  fe->get_phi();
  fe->get_dphi();
  fe->get_xyz();

  FEGenericBase<RealGradient>* side_fe;
  c.get_side_fe<RealGradient>( u_var, side_fe );

  side_fe->get_JxW();
  side_fe->get_phi();
}

bool LaplaceSystem::element_time_derivative (bool request_jacobian,
                                            DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* fe = NULL;
  c.get_element_fe<RealGradient>( u_var, fe );

  // First we get some references to cell-specific data that
  // will be used to assemble the linear system.

  // Element Jacobian * quadrature weights for interior integration
  const std::vector<Real> &JxW = fe->get_JxW();

  // The velocity shape functions at interior quadrature points.
  const std::vector<std::vector<RealGradient> >& phi = fe->get_phi();

  // The velocity shape function gradients at interior
  // quadrature points.
  const std::vector<std::vector<RealTensor> >& grad_phi = fe->get_dphi();

  const std::vector<Point>& qpoint = fe->get_xyz();

  // The number of local degrees of freedom in each variable
  const unsigned int n_u_dofs = c.dof_indices_var[u_var].size();

  DenseSubMatrix<Number> &Kuu = *c.elem_subjacobians[u_var][u_var];

  DenseSubVector<Number> &Fu = *c.elem_subresiduals[u_var];

  // Now we will build the element Jacobian and residual.
  // Constructing the residual requires the solution and its
  // gradient from the previous timestep.  This must be
  // calculated at each quadrature point by summing the
  // solution degree-of-freedom values by the appropriate
  // weight functions.
  const unsigned int n_qpoints = (c.get_element_qrule())->n_points();

  for (unsigned int qp=0; qp != n_qpoints; qp++)
    {
      RealTensor grad_u;

      c.interior_gradient<RealGradient>( u_var, qp, grad_u );

      // Value of the forcing function at this quadrature point
      RealGradient f = this->forcing(qpoint[qp]);

      // First, an i-loop over the velocity degrees of freedom.
      // We know that n_u_dofs == n_v_dofs so we can compute contributions
      // for both at the same time.
      for (unsigned int i=0; i != n_u_dofs; i++)
        {
          Fu(i) += ( grad_u.contract(grad_phi[i][qp]) - f*phi[i][qp] )*JxW[qp];

          if (request_jacobian)
            {
              // Matrix contributions for the uu and vv couplings.
              for (unsigned int j=0; j != n_u_dofs; j++)
                {
                  Kuu(i,j) += grad_phi[j][qp].contract(grad_phi[i][qp])*JxW[qp];

		}
	    }
        }
    } // end of the quadrature point qp-loop

  return request_jacobian;
}

/*
bool LaplaceSystem::side_constraint (bool request_jacobian,
				     DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* side_fe = NULL;
  c.get_side_fe<RealGradient>( u_var, side_fe );

  // First we get some references to cell-specific data that
  // will be used to assemble the linear system.

  // Element Jacobian * quadrature weights for interior integration
  const std::vector<Real> &JxW = side_fe->get_JxW();

  // The velocity shape functions at interior quadrature points.
  const std::vector<std::vector<RealGradient> >& phi = side_fe->get_phi();

  // The number of local degrees of freedom in each variable
  const unsigned int n_u_dofs = c.dof_indices_var[u_var].size();

  const std::vector<Point>& qpoint = side_fe->get_xyz();

  // The penalty value.  \frac{1}{\epsilon}
  // in the discussion above.
  const Real penalty = 1.e10;

  DenseSubMatrix<Number> &Kuu = *c.elem_subjacobians[u_var][u_var];
  DenseSubVector<Number> &Fu = *c.elem_subresiduals[u_var];

  const unsigned int n_qpoints = (c.get_side_qrule())->n_points();

  for (unsigned int qp=0; qp != n_qpoints; qp++)
    {
      RealGradient u;
      c.side_value<RealGradient>( u_var, qp, u );

      RealGradient u_exact( this->exact_solution( 0, qpoint[qp](0), qpoint[qp](1) ),
			    this->exact_solution( 1, qpoint[qp](0), qpoint[qp](1) ));

      for (unsigned int i=0; i != n_u_dofs; i++)
	{
	  Fu(i) += penalty*(u - u_exact)*phi[i][qp]*JxW[qp];

	  if (request_jacobian)
	    {
	      for (unsigned int j=0; j != n_u_dofs; j++)
		Kuu(i,j) += penalty*phi[j][qp]*phi[i][qp]*JxW[qp];
	    }
	}
    }

  return request_jacobian;
}
*/

RealGradient LaplaceSystem::forcing( const Point& p )
{
  Real x = p(0); Real y = p(1); Real z = p(2);

  const Real eps = 1.e-3;

  const Real fx = -(exact_solution(0,x,y,z-eps) +
		    exact_solution(0,x,y,z+eps) +
		    exact_solution(0,x,y-eps,z) +
		    exact_solution(0,x,y+eps,z) +
		    exact_solution(0,x-eps,y,z) +
		    exact_solution(0,x+eps,y,z) -
		    6.*exact_solution(0,x,y,z))/eps/eps;

  const Real fy = -(exact_solution(1,x,y,z-eps) +
		    exact_solution(1,x,y,z+eps) +
		    exact_solution(1,x,y-eps,z) +
		    exact_solution(1,x,y+eps,z) +
		    exact_solution(1,x-eps,y,z) +
		    exact_solution(1,x+eps,y,z) -
		    6.*exact_solution(1,x,y,z))/eps/eps;

  const Real fz = -(exact_solution(2,x,y,z-eps) +
		    exact_solution(2,x,y,z+eps) +
		    exact_solution(2,x,y-eps,z) +
		    exact_solution(2,x,y+eps,z) +
		    exact_solution(2,x-eps,y,z) +
		    exact_solution(2,x+eps,y,z) -
		    6.*exact_solution(2,x,y,z))/eps/eps;

  return RealGradient( fx, fy, fz );
}
<commit_msg>Fix for --enable-complex<commit_after>/* The Next Great Finite Element Library. */
/* Copyright (C) 2003  Benjamin S. Kirk */

/* This library is free software; you can redistribute it and/or */
/* modify it under the terms of the GNU Lesser General Public */
/* License as published by the Free Software Foundation; either */
/* version 2.1 of the License, or (at your option) any later version. */

/* This library is distributed in the hope that it will be useful, */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU */
/* Lesser General Public License for more details. */

/* You should have received a copy of the GNU Lesser General Public */
/* License along with this library; if not, write to the Free Software */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "getpot.h"

#include "laplace_system.h"

#include "boundary_info.h"
#include "dof_map.h"
#include "fe_base.h"
#include "fe_interface.h"
#include "fem_context.h"
#include "mesh.h"
#include "quadrature.h"
#include "string_to_enum.h"

// Bring in everything from the libMesh namespace
using namespace libMesh;

LaplaceSystem::LaplaceSystem( EquationSystems& es,
			      const std::string& name,
			      const unsigned int number)
  : FEMSystem(es, name, number)
{
  return;
}

void LaplaceSystem::init_data ()
{
  // Check the input file for Reynolds number, application type,
  // approximation type
  GetPot infile("laplace.in");

  // Add the solution variable
  u_var = this->add_variable ("u", SECOND, LAGRANGE_VEC);

  this->time_evolving(u_var);

  // Useful debugging options
  // Set verify_analytic_jacobians to 1e-6 to use
  this->verify_analytic_jacobians = infile("verify_analytic_jacobians", 0.);
  this->print_jacobians = infile("print_jacobians", false);
  this->print_element_jacobians = infile("print_element_jacobians", false);

  this->init_dirichlet_bcs();

  // Do the parent's initialization after variables and boundary constraints are defined
  FEMSystem::init_data();
}

void LaplaceSystem::init_dirichlet_bcs()
{
  const boundary_id_type all_ids[6] = {0,1,2,3,4,5};
  std::set<boundary_id_type> boundary_ids( all_ids, all_ids+6 );

  std::vector<unsigned int> vars;
  vars.push_back( u_var );

  BoundaryFunction func( u_var );

  this->get_dof_map().add_dirichlet_boundary( libMesh::DirichletBoundary( boundary_ids, vars, &func ) );
  return;
}

void LaplaceSystem::init_context(DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* fe;
  c.get_element_fe<RealGradient>( u_var, fe );

  // We should prerequest all the data
  // we will need to build the linear system.
  fe->get_JxW();
  fe->get_phi();
  fe->get_dphi();
  fe->get_xyz();

  FEGenericBase<RealGradient>* side_fe;
  c.get_side_fe<RealGradient>( u_var, side_fe );

  side_fe->get_JxW();
  side_fe->get_phi();
}

bool LaplaceSystem::element_time_derivative (bool request_jacobian,
                                            DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* fe = NULL;
  c.get_element_fe<RealGradient>( u_var, fe );

  // First we get some references to cell-specific data that
  // will be used to assemble the linear system.

  // Element Jacobian * quadrature weights for interior integration
  const std::vector<Real> &JxW = fe->get_JxW();

  // The velocity shape functions at interior quadrature points.
  const std::vector<std::vector<RealGradient> >& phi = fe->get_phi();

  // The velocity shape function gradients at interior
  // quadrature points.
  const std::vector<std::vector<RealTensor> >& grad_phi = fe->get_dphi();

  const std::vector<Point>& qpoint = fe->get_xyz();

  // The number of local degrees of freedom in each variable
  const unsigned int n_u_dofs = c.dof_indices_var[u_var].size();

  DenseSubMatrix<Number> &Kuu = *c.elem_subjacobians[u_var][u_var];

  DenseSubVector<Number> &Fu = *c.elem_subresiduals[u_var];

  // Now we will build the element Jacobian and residual.
  // Constructing the residual requires the solution and its
  // gradient from the previous timestep.  This must be
  // calculated at each quadrature point by summing the
  // solution degree-of-freedom values by the appropriate
  // weight functions.
  const unsigned int n_qpoints = (c.get_element_qrule())->n_points();

  for (unsigned int qp=0; qp != n_qpoints; qp++)
    {
      Tensor grad_u;

      c.interior_gradient<RealGradient>( u_var, qp, grad_u );

      // Value of the forcing function at this quadrature point
      RealGradient f = this->forcing(qpoint[qp]);

      // First, an i-loop over the velocity degrees of freedom.
      // We know that n_u_dofs == n_v_dofs so we can compute contributions
      // for both at the same time.
      for (unsigned int i=0; i != n_u_dofs; i++)
        {
          Fu(i) += ( grad_u.contract(grad_phi[i][qp]) - f*phi[i][qp] )*JxW[qp];

          if (request_jacobian)
            {
              // Matrix contributions for the uu and vv couplings.
              for (unsigned int j=0; j != n_u_dofs; j++)
                {
                  Kuu(i,j) += grad_phi[j][qp].contract(grad_phi[i][qp])*JxW[qp];

		}
	    }
        }
    } // end of the quadrature point qp-loop

  return request_jacobian;
}

/*
bool LaplaceSystem::side_constraint (bool request_jacobian,
				     DiffContext &context)
{
  FEMContext &c = libmesh_cast_ref<FEMContext&>(context);

  // Get finite element object
  FEGenericBase<RealGradient>* side_fe = NULL;
  c.get_side_fe<RealGradient>( u_var, side_fe );

  // First we get some references to cell-specific data that
  // will be used to assemble the linear system.

  // Element Jacobian * quadrature weights for interior integration
  const std::vector<Real> &JxW = side_fe->get_JxW();

  // The velocity shape functions at interior quadrature points.
  const std::vector<std::vector<RealGradient> >& phi = side_fe->get_phi();

  // The number of local degrees of freedom in each variable
  const unsigned int n_u_dofs = c.dof_indices_var[u_var].size();

  const std::vector<Point>& qpoint = side_fe->get_xyz();

  // The penalty value.  \frac{1}{\epsilon}
  // in the discussion above.
  const Real penalty = 1.e10;

  DenseSubMatrix<Number> &Kuu = *c.elem_subjacobians[u_var][u_var];
  DenseSubVector<Number> &Fu = *c.elem_subresiduals[u_var];

  const unsigned int n_qpoints = (c.get_side_qrule())->n_points();

  for (unsigned int qp=0; qp != n_qpoints; qp++)
    {
      RealGradient u;
      c.side_value<RealGradient>( u_var, qp, u );

      RealGradient u_exact( this->exact_solution( 0, qpoint[qp](0), qpoint[qp](1) ),
			    this->exact_solution( 1, qpoint[qp](0), qpoint[qp](1) ));

      for (unsigned int i=0; i != n_u_dofs; i++)
	{
	  Fu(i) += penalty*(u - u_exact)*phi[i][qp]*JxW[qp];

	  if (request_jacobian)
	    {
	      for (unsigned int j=0; j != n_u_dofs; j++)
		Kuu(i,j) += penalty*phi[j][qp]*phi[i][qp]*JxW[qp];
	    }
	}
    }

  return request_jacobian;
}
*/

RealGradient LaplaceSystem::forcing( const Point& p )
{
  Real x = p(0); Real y = p(1); Real z = p(2);

  const Real eps = 1.e-3;

  const Real fx = -(exact_solution(0,x,y,z-eps) +
		    exact_solution(0,x,y,z+eps) +
		    exact_solution(0,x,y-eps,z) +
		    exact_solution(0,x,y+eps,z) +
		    exact_solution(0,x-eps,y,z) +
		    exact_solution(0,x+eps,y,z) -
		    6.*exact_solution(0,x,y,z))/eps/eps;

  const Real fy = -(exact_solution(1,x,y,z-eps) +
		    exact_solution(1,x,y,z+eps) +
		    exact_solution(1,x,y-eps,z) +
		    exact_solution(1,x,y+eps,z) +
		    exact_solution(1,x-eps,y,z) +
		    exact_solution(1,x+eps,y,z) -
		    6.*exact_solution(1,x,y,z))/eps/eps;

  const Real fz = -(exact_solution(2,x,y,z-eps) +
		    exact_solution(2,x,y,z+eps) +
		    exact_solution(2,x,y-eps,z) +
		    exact_solution(2,x,y+eps,z) +
		    exact_solution(2,x-eps,y,z) +
		    exact_solution(2,x+eps,y,z) -
		    6.*exact_solution(2,x,y,z))/eps/eps;

  return RealGradient( fx, fy, fz );
}
<|endoftext|>


<commit_before><commit_msg>Scont.hpp, now with functor reuse!<commit_after><|endoftext|>