work-in-progress

add UDP network connection for physics client <-> server.
also set spinning friction in rolling friction demo (otherwise objects may keep on spinning forever)
This commit is contained in:
erwincoumans
2016-11-04 13:15:10 -07:00
parent c2ca88bf44
commit 9708392322
52 changed files with 2104 additions and 214 deletions

View File

@@ -73,8 +73,8 @@
newoption
{
trigger = "enet",
description = "Enable enet NAT punchthrough test"
trigger = "no-enet",
description = "Disable enet and enet tests"
}
newoption
@@ -261,14 +261,19 @@ end
if not _OPTIONS["no-test"] then
include "../test/SharedMemory"
if _OPTIONS["enet"] then
include "../examples/ThirdPartyLibs/enet"
include "../test/enet/client"
include "../test/enet/server"
end
end
end
if not _OPTIONS["no-enet"] then
include "../examples/ThirdPartyLibs/enet"
include "../test/enet/nat_punchthrough/client"
include "../test/enet/nat_punchthrough/server"
include "../test/enet/chat/client"
include "../test/enet/chat/server"
defines {"BT_ENABLE_ENET"}
end
if _OPTIONS["no-bullet3"] then
print "--no-bullet3 implies --no-demos"
_OPTIONS["no-demos"] = "1"

View File

@@ -0,0 +1,4 @@
mkdir cm
cd cm
cmake -DBUILD_PYBULLET=ON -DCMAKE_BUILD_TYPE=Release -DPYTHON_INCLUDE_DIR=c:\python-3.5.2\include -DPYTHON_LIBRARY=c:\python-3.5.2\libs\python35_d.lib ..
start .

View File

@@ -146,6 +146,7 @@ SET(BulletExampleBrowser_SRCS
../SharedMemory/PhysicsServer.cpp
../SharedMemory/PhysicsClientSharedMemory.cpp
../SharedMemory/PhysicsClientSharedMemory_C_API.cpp
../SharedMemory/PhysicsClient.cpp
../SharedMemory/PhysicsClientC_API.cpp
../SharedMemory/PhysicsServerExample.cpp

View File

@@ -134,9 +134,9 @@ int gSharedMemoryKey=-1;
int gPreferredOpenCLDeviceIndex=-1;
int gPreferredOpenCLPlatformIndex=-1;
int gGpuArraySizeX=15;
int gGpuArraySizeY=15;
int gGpuArraySizeZ=15;
int gGpuArraySizeX=45;
int gGpuArraySizeY=55;
int gGpuArraySizeZ=45;
//#include <float.h>
//unsigned int fp_control_state = _controlfp(_EM_INEXACT, _MCW_EM);

View File

@@ -15,6 +15,8 @@
#include "../Importers/ImportURDFDemo/ImportURDFSetup.h"
#include "../Importers/ImportSDFDemo/ImportSDFSetup.h"
#include "../Importers/ImportSTLDemo/ImportSTLSetup.h"
#include "../Importers/ImportBullet/SerializeSetup.h"
#include "LinearMath/btAlignedAllocator.h"
@@ -34,6 +36,8 @@ int main(int argc, char* argv[])
exampleBrowser->registerFileImporter(".sdf", ImportSDFCreateFunc);
exampleBrowser->registerFileImporter(".obj", ImportObjCreateFunc);
exampleBrowser->registerFileImporter(".stl", ImportSTLCreateFunc);
exampleBrowser->registerFileImporter(".bullet", SerializeBulletCreateFunc);
clock.reset();
if (init)

View File

@@ -63,6 +63,14 @@ project "App_BulletExampleBrowser"
"../SharedMemory/PhysicsServer.cpp",
"../SharedMemory/PhysicsServerSharedMemory.cpp",
"../SharedMemory/PhysicsClientSharedMemory.cpp",
"../SharedMemory/PhysicsClientSharedMemory_C_API.cpp",
"../SharedMemory/PhysicsClientSharedMemory_C_API.h",
"../SharedMemory/PhysicsClientSharedMemory2.cpp",
"../SharedMemory/PhysicsClientSharedMemory2.h",
"../SharedMemory/PhysicsClientSharedMemory2_C_API.cpp",
"../SharedMemory/PhysicsClientSharedMemory2_C_API.h",
"../SharedMemory/SharedMemoryCommandProcessor.cpp",
"../SharedMemory/SharedMemoryCommandProcessor.h",
"../SharedMemory/SharedMemoryInProcessPhysicsC_API.cpp",
"../SharedMemory/PhysicsClient.cpp",
"../SharedMemory/PosixSharedMemory.cpp",

View File

@@ -11,6 +11,7 @@
#include "stb_image/stb_image.h"
#include "Bullet3Common/b3Quaternion.h"
#include "Bullet3Common/b3Matrix3x3.h"
#include "../Utils/b3Clock.h"
#include "../CommonInterfaces/CommonParameterInterface.h"
#include "LinearMath/btAlignedObjectArray.h"
@@ -134,6 +135,8 @@ void SampleThreadFunc(void* userPtr,void* lsMemory)
job->executeJob(localStorage->threadId);
}
b3Clock::usleep(250);
args->m_cs->lock();
int exitMagicNumber = args->m_cs->getSharedParam(1);
requestExit = (exitMagicNumber==MAGIC_RESET_NUMBER);

View File

@@ -17,9 +17,9 @@ subject to the following restrictions:
///todo: make this configurable in the gui
bool useShadowMap = true;// true;//false;//true;
int shadowMapWidth= 2048;
int shadowMapHeight= 2048;
float shadowMapWorldSize=5;
int shadowMapWidth= 4096;
int shadowMapHeight= 4096;
float shadowMapWorldSize=10;
#define MAX_POINTS_IN_BATCH 1024
#define MAX_LINES_IN_BATCH 1024
@@ -1539,7 +1539,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode)
b3Assert(glGetError() ==GL_NO_ERROR);
} else
{
//glDisable(GL_CULL_FACE);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
}

View File

@@ -5,6 +5,8 @@
#include "Bullet3Common/b3AlignedObjectArray.h"
#include "../CommonInterfaces/CommonRenderInterface.h"
//#include "../CommonInterfaces/CommonExampleInterface.h"
#include "../SharedMemory/PhysicsServerCommandProcessor.h"
#include "../CommonInterfaces/CommonGUIHelperInterface.h"
#include "../SharedMemory/PhysicsServerSharedMemory.h"
#include "../SharedMemory/PhysicsServerSharedMemory.h"
@@ -893,7 +895,8 @@ bool b3RobotSimAPI::connect(GUIHelperInterface* guiHelper)
}
else
{
m_data->m_clientServerDirect = new PhysicsDirect();
PhysicsServerCommandProcessor* sdk = new PhysicsServerCommandProcessor;
m_data->m_clientServerDirect = new PhysicsDirect(sdk);
bool connected = m_data->m_clientServerDirect->connect(guiHelper);
m_data->m_physicsClient = (b3PhysicsClientHandle)m_data->m_clientServerDirect;

View File

@@ -123,8 +123,8 @@ void RollingFrictionDemo::initPhysics()
btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);
btRigidBody* body = new btRigidBody(rbInfo);
body->setFriction(1);
body->setRollingFriction(1);
body->setFriction(.5);
//add the body to the dynamics world
m_dynamicsWorld->addRigidBody(body);
}
@@ -153,8 +153,7 @@ void RollingFrictionDemo::initPhysics()
btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);
btRigidBody* body = new btRigidBody(rbInfo);
body->setFriction(1);
body->setRollingFriction(1);
body->setFriction(.1);
//add the body to the dynamics world
m_dynamicsWorld->addRigidBody(body);
}
@@ -217,7 +216,8 @@ void RollingFrictionDemo::initPhysics()
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia);
btRigidBody* body = new btRigidBody(rbInfo);
body->setFriction(1.f);
body->setRollingFriction(.3);
body->setRollingFriction(.1);
body->setSpinningFriction(0.1);
body->setAnisotropicFriction(colShape->getAnisotropicRollingFrictionDirection(),btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);

View File

@@ -58,21 +58,25 @@ b3SharedMemoryCommandHandle b3LoadUrdfCommandInit(b3PhysicsClientHandle physClie
b3Assert(cl);
b3Assert(cl->canSubmitCommand());
if (cl->canSubmitCommand())
{
struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand();
b3Assert(command);
command->m_type = CMD_LOAD_URDF;
int len = strlen(urdfFileName);
if (len < MAX_URDF_FILENAME_LENGTH)
{
strcpy(command->m_urdfArguments.m_urdfFileName, urdfFileName);
}
else
{
command->m_urdfArguments.m_urdfFileName[0] = 0;
}
command->m_updateFlags = URDF_ARGS_FILE_NAME;
struct SharedMemoryCommand* command = cl->getAvailableSharedMemoryCommand();
b3Assert(command);
command->m_type = CMD_LOAD_URDF;
int len = strlen(urdfFileName);
if (len<MAX_URDF_FILENAME_LENGTH)
{
strcpy(command->m_urdfArguments.m_urdfFileName,urdfFileName);
} else
{
command->m_urdfArguments.m_urdfFileName[0] = 0;
return (b3SharedMemoryCommandHandle)command;
}
command->m_updateFlags = URDF_ARGS_FILE_NAME;
return (b3SharedMemoryCommandHandle) command;
return 0;
}
b3SharedMemoryCommandHandle b3LoadBunnyCommandInit(b3PhysicsClientHandle physClient)
@@ -116,35 +120,52 @@ int b3LoadUrdfCommandSetUseFixedBase(b3SharedMemoryCommandHandle commandHandle,
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle;
b3Assert(command);
b3Assert(command->m_type == CMD_LOAD_URDF);
command->m_updateFlags |=URDF_ARGS_USE_FIXED_BASE;
command->m_urdfArguments.m_useFixedBase = useFixedBase;
return 0;
if (command && (command->m_type == CMD_LOAD_URDF))
{
command->m_updateFlags |= URDF_ARGS_USE_FIXED_BASE;
command->m_urdfArguments.m_useFixedBase = useFixedBase;
return 0;
}
return -1;
}
int b3LoadUrdfCommandSetStartPosition(b3SharedMemoryCommandHandle commandHandle, double startPosX,double startPosY,double startPosZ)
{
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle;
b3Assert(command);
b3Assert(command->m_type == CMD_LOAD_URDF);
command->m_urdfArguments.m_initialPosition[0] = startPosX;
command->m_urdfArguments.m_initialPosition[1] = startPosY;
command->m_urdfArguments.m_initialPosition[2] = startPosZ;
command->m_updateFlags|=URDF_ARGS_INITIAL_POSITION;
return 0;
if (command)
{
b3Assert(command->m_type == CMD_LOAD_URDF);
if (command->m_type == CMD_LOAD_URDF)
{
command->m_urdfArguments.m_initialPosition[0] = startPosX;
command->m_urdfArguments.m_initialPosition[1] = startPosY;
command->m_urdfArguments.m_initialPosition[2] = startPosZ;
command->m_updateFlags |= URDF_ARGS_INITIAL_POSITION;
}
return 0;
}
return -1;
}
int b3LoadUrdfCommandSetStartOrientation(b3SharedMemoryCommandHandle commandHandle, double startOrnX,double startOrnY,double startOrnZ, double startOrnW)
{
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle;
b3Assert(command);
b3Assert(command->m_type == CMD_LOAD_URDF);
command->m_urdfArguments.m_initialOrientation[0] = startOrnX;
command->m_urdfArguments.m_initialOrientation[1] = startOrnY;
command->m_urdfArguments.m_initialOrientation[2] = startOrnZ;
command->m_urdfArguments.m_initialOrientation[3] = startOrnW;
command->m_updateFlags|=URDF_ARGS_INITIAL_ORIENTATION;
return 0;
if (command)
{
b3Assert(command->m_type == CMD_LOAD_URDF);
if (command->m_type == CMD_LOAD_URDF)
{
command->m_urdfArguments.m_initialOrientation[0] = startOrnX;
command->m_urdfArguments.m_initialOrientation[1] = startOrnY;
command->m_urdfArguments.m_initialOrientation[2] = startOrnZ;
command->m_urdfArguments.m_initialOrientation[3] = startOrnW;
command->m_updateFlags |= URDF_ARGS_INITIAL_ORIENTATION;
}
return 0;
}
return -1;
}
b3SharedMemoryCommandHandle b3InitPhysicsParamCommand(b3PhysicsClientHandle physClient)
@@ -174,7 +195,7 @@ int b3PhysicsParamSetRealTimeSimulation(b3SharedMemoryCommandHandle commandH
{
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle;
b3Assert(command->m_type == CMD_SEND_PHYSICS_SIMULATION_PARAMETERS);
command->m_physSimParamArgs.m_allowRealTimeSimulation = enableRealTimeSimulation;
command->m_physSimParamArgs.m_allowRealTimeSimulation = (enableRealTimeSimulation!=0);
command->m_updateFlags |= SIM_PARAM_UPDATE_REAL_TIME_SIMULATION;
return 0;
}
@@ -621,20 +642,11 @@ int b3CreateSensorEnableIMUForLink(b3SharedMemoryCommandHandle commandHandle, in
}
b3PhysicsClientHandle b3ConnectSharedMemory(int key)
{
PhysicsClientSharedMemory* cl = new PhysicsClientSharedMemory();
///client should never create shared memory, only the server does
cl->setSharedMemoryKey(key);
cl->connect();
return (b3PhysicsClientHandle ) cl;
}
void b3DisconnectSharedMemory(b3PhysicsClientHandle physClient)
{
PhysicsClient* cl = (PhysicsClient* ) physClient;
cl->disconnectSharedMemory();
delete cl;
}
@@ -772,22 +784,34 @@ int b3SubmitClientCommand(b3PhysicsClientHandle physClient, const b3SharedMemory
{
struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle;
PhysicsClient* cl = (PhysicsClient* ) physClient;
return (int)cl->submitClientCommand(*command);
b3Assert(command);
b3Assert(cl);
if (command && cl)
{
return (int)cl->submitClientCommand(*command);
}
return -1;
}
b3SharedMemoryStatusHandle b3SubmitClientCommandAndWaitStatus(b3PhysicsClientHandle physClient, const b3SharedMemoryCommandHandle commandHandle)
{
int timeout = 1024*1024*1024;
b3SharedMemoryStatusHandle statusHandle=0;
int timeout = 1024 * 1024 * 1024;
b3SharedMemoryStatusHandle statusHandle = 0;
b3Assert(commandHandle);
b3Assert(physClient);
if (physClient && commandHandle)
{
b3SubmitClientCommand(physClient, commandHandle);
b3SubmitClientCommand(physClient,commandHandle);
while ((statusHandle==0) && (timeout-- > 0))
{
statusHandle =b3ProcessServerStatus(physClient);
}
return (b3SharedMemoryStatusHandle) statusHandle;
while ((statusHandle == 0) && (timeout-- > 0))
{
statusHandle = b3ProcessServerStatus(physClient);
}
return (b3SharedMemoryStatusHandle)statusHandle;
}
return 0;
}

View File

@@ -11,14 +11,18 @@ B3_DECLARE_HANDLE(b3SharedMemoryCommandHandle);
B3_DECLARE_HANDLE(b3SharedMemoryStatusHandle);
///There are several connection methods, see following header files:
#include "PhysicsClientSharedMemory_C_API.h"
#include "PhysicsClientSharedMemory2_C_API.h"
#include "PhysicsDirectC_API.h"
#include "PhysicsClientUDP_C_API.h"
#include "SharedMemoryInProcessPhysicsC_API.h"
#ifdef __cplusplus
extern "C" {
#endif
///b3ConnectSharedMemory will connect to a physics server over shared memory, so
///make sure to start the server first.
///and a way to spawn an OpenGL 3D GUI physics server and connect (b3CreateInProcessPhysicsServerAndConnect)
b3PhysicsClientHandle b3ConnectSharedMemory(int key);
///b3DisconnectSharedMemory will disconnect the client from the server and cleanup memory.
void b3DisconnectSharedMemory(b3PhysicsClientHandle physClient);

View File

@@ -124,8 +124,11 @@ bool PhysicsClientSharedMemory::getJointInfo(int bodyUniqueId, int jointIndex, b
if (bodyJointsPtr && *bodyJointsPtr)
{
BodyJointInfoCache* bodyJoints = *bodyJointsPtr;
info = bodyJoints->m_jointInfo[jointIndex];
return true;
if ((jointIndex >= 0) && (jointIndex < bodyJoints->m_jointInfo.size()))
{
info = bodyJoints->m_jointInfo[jointIndex];
return true;
}
}
return false;
}
@@ -210,7 +213,7 @@ void PhysicsClientSharedMemory::processBodyJointInfo(int bodyUniqueId, const Sha
{
bParse::btBulletFile bf(
&this->m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor[0],
serverCmd.m_dataStreamArguments.m_streamChunkLength);
serverCmd.m_numDataStreamBytes);
bf.setFileDNAisMemoryDNA();
bf.parse(false);
@@ -291,16 +294,17 @@ const SharedMemoryStatus* PhysicsClientSharedMemory::processServerStatus() {
break;
}
case CMD_URDF_LOADING_COMPLETED: {
if (m_data->m_verboseOutput) {
b3Printf("Server loading the URDF OK\n");
}
if (serverCmd.m_dataStreamArguments.m_streamChunkLength > 0) {
if (serverCmd.m_numDataStreamBytes > 0) {
bParse::btBulletFile bf(
this->m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor,
serverCmd.m_dataStreamArguments.m_streamChunkLength);
serverCmd.m_numDataStreamBytes);
bf.setFileDNAisMemoryDNA();
bf.parse(false);
int bodyUniqueId = serverCmd.m_dataStreamArguments.m_bodyUniqueId;

View File

@@ -0,0 +1,27 @@
#include "PhysicsClientSharedMemory2.h"
#include "PosixSharedMemory.h"
#include "Win32SharedMemory.h"
#include "Bullet3Common/b3Logging.h"
#include "Bullet3Common/b3Scalar.h"
#include "SharedMemoryCommandProcessor.h"
PhysicsClientSharedMemory2::PhysicsClientSharedMemory2(SharedMemoryCommandProcessor* proc)
:PhysicsDirect(proc)
{
m_proc = proc;
}
PhysicsClientSharedMemory2::~PhysicsClientSharedMemory2()
{
}
void PhysicsClientSharedMemory2::setSharedMemoryInterface(class SharedMemoryInterface* sharedMem)
{
if (m_proc)
{
m_proc->setSharedMemoryInterface(sharedMem);
}
}

View File

@@ -0,0 +1,18 @@
#ifndef PHYSICS_CLIENT_SHARED_MEMORY2_H
#define PHYSICS_CLIENT_SHARED_MEMORY2_H
#include "PhysicsDirect.h"
class PhysicsClientSharedMemory2 : public PhysicsDirect
{
class SharedMemoryCommandProcessor* m_proc;
public:
PhysicsClientSharedMemory2(SharedMemoryCommandProcessor* proc);
virtual ~PhysicsClientSharedMemory2();
void setSharedMemoryInterface(class SharedMemoryInterface* sharedMem);
};
#endif //PHYSICS_CLIENT_SHARED_MEMORY2_H

View File

@@ -0,0 +1,19 @@
#include "PhysicsClientSharedMemory2_C_API.h"
#include "PhysicsDirect.h"
#include "SharedMemoryCommandProcessor.h"
b3PhysicsClientHandle b3ConnectSharedMemory2(int key)
{
SharedMemoryCommandProcessor* cmdProc = new SharedMemoryCommandProcessor();
cmdProc->setSharedMemoryKey(key);
PhysicsDirect* cl = new PhysicsDirect(cmdProc);
cl->setSharedMemoryKey(key);
cl->connect();
return (b3PhysicsClientHandle)cl;
}

View File

@@ -0,0 +1,18 @@
#ifndef PHYSICS_CLIENT_SHARED_MEMORY2_H
#define PHYSICS_CLIENT_SHARED_MEMORY2_H
#include "PhysicsClientC_API.h"
#ifdef __cplusplus
extern "C" {
#endif
b3PhysicsClientHandle b3ConnectSharedMemory2(int key);
#ifdef __cplusplus
}
#endif
#endif //PHYSICS_CLIENT_SHARED_MEMORY2_H

View File

@@ -0,0 +1,11 @@
#include "PhysicsClientSharedMemory_C_API.h"
#include "PhysicsClientSharedMemory.h"
b3PhysicsClientHandle b3ConnectSharedMemory(int key)
{
PhysicsClientSharedMemory* cl = new PhysicsClientSharedMemory();
cl->setSharedMemoryKey(key);
cl->connect();
return (b3PhysicsClientHandle)cl;
}

View File

@@ -0,0 +1,16 @@
#ifndef PHYSICS_CLIENT_SHARED_MEMORY_H
#define PHYSICS_CLIENT_SHARED_MEMORY_H
#include "PhysicsClientC_API.h"
#ifdef __cplusplus
extern "C" {
#endif
b3PhysicsClientHandle b3ConnectSharedMemory(int key);
#ifdef __cplusplus
}
#endif
#endif //PHYSICS_CLIENT_SHARED_MEMORY_H

View File

@@ -0,0 +1,577 @@
#include "PhysicsClientUDP.h"
#include <enet/enet.h>
#include <stdio.h>
#include <string.h>
#include "../Utils/b3Clock.h"
#include "PhysicsClient.h"
//#include "LinearMath/btVector3.h"
#include "SharedMemoryCommands.h"
#include <string>
#include "Bullet3Common/b3Logging.h"
#include "../MultiThreading/b3ThreadSupportInterface.h"
void UDPThreadFunc(void* userPtr, void* lsMemory);
void* UDPlsMemoryFunc();
#ifndef _WIN32
#include "../MultiThreading/b3PosixThreadSupport.h"
b3ThreadSupportInterface* createUDPThreadSupport(int numThreads)
{
b3PosixThreadSupport::ThreadConstructionInfo constructionInfo("UDPThread",
UDPThreadFunc,
UDPlsMemoryFunc,
numThreads);
b3ThreadSupportInterface* threadSupport = new b3PosixThreadSupport(constructionInfo);
return threadSupport;
}
#elif defined( _WIN32)
#include "../MultiThreading/b3Win32ThreadSupport.h"
b3ThreadSupportInterface* createUDPThreadSupport(int numThreads)
{
b3Win32ThreadSupport::Win32ThreadConstructionInfo threadConstructionInfo("UDPThread", UDPThreadFunc, UDPlsMemoryFunc, numThreads);
b3Win32ThreadSupport* threadSupport = new b3Win32ThreadSupport(threadConstructionInfo);
return threadSupport;
}
#endif
struct UDPThreadLocalStorage
{
int threadId;
};
unsigned int b3DeserializeInt(const unsigned char* input)
{
unsigned int tmp = (input[3] << 24) + (input[2] << 16) + (input[1] << 8) + input[0];
return tmp;
}
struct UdpNetworkedInternalData
{
ENetHost* m_client;
ENetAddress m_address;
ENetPeer* m_peer;
ENetEvent m_event;
bool m_isConnected;
b3ThreadSupportInterface* m_threadSupport;
b3CriticalSection* m_cs;
UdpNetworkedInternalData* m_udpInternalData;
SharedMemoryCommand m_clientCmd;
bool m_hasCommand;
bool m_hasStatus;
SharedMemoryStatus m_lastStatus;
b3AlignedObjectArray<char> m_stream;
std::string m_hostName;
int m_port;
UdpNetworkedInternalData()
:m_client(0),
m_peer(0),
m_isConnected(false),
m_threadSupport(0),
m_hasCommand(false),
m_hasStatus(false)
{
}
bool connectUDP()
{
if (m_isConnected)
return true;
if (enet_initialize() != 0)
{
fprintf(stderr, "Error initialising enet");
exit(EXIT_FAILURE);
}
m_client = enet_host_create(NULL, /* create a client host */
1, /* number of clients */
2, /* number of channels */
57600 / 8, /* incoming bandwith */
14400 / 8); /* outgoing bandwith */
if (m_client == NULL) {
fprintf(stderr, "Could not create client host");
return false;
}
enet_address_set_host(&m_address, m_hostName.c_str());
m_address.port = m_port;
m_peer = enet_host_connect(m_client,
&m_address, /* address to connect to */
2, /* number of channels */
0); /* user data supplied to
the receiving host */
if (m_peer == NULL) {
fprintf(stderr, "No available peers for initiating an ENet "
"connection.\n");
return false;
}
/* Try to connect to server within 5 seconds */
if (enet_host_service(m_client, &m_event, 5000) > 0 &&
m_event.type == ENET_EVENT_TYPE_CONNECT)
{
puts("Connection to server succeeded.");
}
else
{
/* Either the 5 seconds are up or a disconnect event was */
/* received. Reset the peer in the event the 5 seconds */
/* had run out without any significant event. */
enet_peer_reset(m_peer);
fprintf(stderr, "Connection to server failed.");
return false;
}
int serviceResult = enet_host_service(m_client, &m_event, 0);
if (serviceResult > 0)
{
switch (m_event.type)
{
case ENET_EVENT_TYPE_CONNECT:
printf("A new client connected from %x:%u.\n",
m_event.peer->address.host,
m_event.peer->address.port);
m_event.peer->data = (void*)"New User";
break;
case ENET_EVENT_TYPE_RECEIVE:
printf("A packet of length %u containing '%s' was "
"received from %s on channel %u.\n",
m_event.packet->dataLength,
m_event.packet->data,
m_event.peer->data,
m_event.channelID);
/* Clean up the packet now that we're done using it.
> */
enet_packet_destroy(m_event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
printf("%s disconected.\n", m_event.peer->data);
break;
}
}
else if (serviceResult > 0)
{
puts("Error with servicing the client");
return false;
}
m_isConnected = true;
return m_isConnected;
}
bool checkData()
{
bool hasStatus = false;
int serviceResult = enet_host_service(m_client, &m_event, 100);
if (serviceResult > 0)
{
switch (m_event.type)
{
case ENET_EVENT_TYPE_CONNECT:
printf("A new client connected from %x:%u.\n",
m_event.peer->address.host,
m_event.peer->address.port);
m_event.peer->data = (void*)"New User";
break;
case ENET_EVENT_TYPE_RECEIVE:
{
printf("A packet of length %u containing '%s' was "
"received from %s on channel %u.\n",
m_event.packet->dataLength,
m_event.packet->data,
m_event.peer->data,
m_event.channelID);
int packetSizeInBytes = b3DeserializeInt(m_event.packet->data);
if (packetSizeInBytes == m_event.packet->dataLength)
{
SharedMemoryStatus* statPtr = (SharedMemoryStatus*)&m_event.packet->data[4];
m_lastStatus = *statPtr;
int streamOffsetInBytes = 4 + sizeof(SharedMemoryStatus);
int numStreamBytes = packetSizeInBytes - streamOffsetInBytes;
m_stream.resize(numStreamBytes);
for (int i = 0; i < numStreamBytes; i++)
{
m_stream[i] = m_event.packet->data[i + streamOffsetInBytes];
}
}
else
{
printf("unknown status message received\n");
}
enet_packet_destroy(m_event.packet);
hasStatus = true;
break;
}
case ENET_EVENT_TYPE_DISCONNECT:
{
printf("%s disconected.\n", m_event.peer->data);
break;
}
}
}
else if (serviceResult > 0)
{
puts("Error with servicing the client");
}
return hasStatus;
}
};
enum UDPThreadEnums
{
eUDPRequestTerminate = 13,
eUDPIsUnInitialized,
eUDPIsInitialized,
eUDPInitializationFailed,
eUDPHasTerminated
};
enum UDPCommandEnums
{
eUDPIdle = 13,
eUDP_ConnectRequest,
eUDP_Connected,
eUDP_ConnectionFailed,
eUDP_DisconnectRequest,
eUDP_Disconnected,
};
void UDPThreadFunc(void* userPtr, void* lsMemory)
{
printf("UDPThreadFunc thread started\n");
UDPThreadLocalStorage* localStorage = (UDPThreadLocalStorage*)lsMemory;
UdpNetworkedInternalData* args = (UdpNetworkedInternalData*)userPtr;
int workLeft = true;
b3Clock clock;
clock.reset();
bool init = true;
if (init)
{
args->m_cs->lock();
args->m_cs->setSharedParam(0, eUDPIsInitialized);
args->m_cs->unlock();
double deltaTimeInSeconds = 0;
do
{
deltaTimeInSeconds += double(clock.getTimeMicroseconds()) / 1000000.;
if (deltaTimeInSeconds<(1. / 5000.))
{
// b3Clock::usleep(250);
}
else
{
clock.reset();
deltaTimeInSeconds = 0.f;
switch (args->m_cs->getSharedParam(1))
{
case eUDP_ConnectRequest:
{
bool connected = args->connectUDP();
if (connected)
{
args->m_cs->setSharedParam(1, eUDP_Connected);
}
else
{
args->m_cs->setSharedParam(1, eUDP_ConnectionFailed);
}
break;
}
default:
{
}
};
if (args->m_isConnected)
{
args->m_cs->lock();
bool hasCommand = args->m_hasCommand;
args->m_cs->unlock();
if (hasCommand)
{
int sz = sizeof(SharedMemoryCommand);
ENetPacket *packet = enet_packet_create(&args->m_clientCmd, sz, ENET_PACKET_FLAG_RELIABLE);
int res = enet_peer_send(args->m_peer, 0, packet);
args->m_cs->lock();
args->m_hasCommand = false;
args->m_cs->unlock();
}
bool hasNewStatus = args->checkData();
if (hasNewStatus)
{
if (args->m_hasStatus)
{
//overflow: last status hasn't been processed yet
b3Assert(0);
printf("Error: received new status but previous status not processed yet");
}
else
{
args->m_cs->lock();
args->m_hasStatus = hasNewStatus;
args->m_cs->unlock();
}
}
}
}
} while (args->m_cs->getSharedParam(0) != eUDPRequestTerminate);
}
else
{
args->m_cs->lock();
args->m_cs->setSharedParam(0, eUDPInitializationFailed);
args->m_cs->unlock();
}
printf("finished\n");
}
void* UDPlsMemoryFunc()
{
//don't create local store memory, just return 0
return new UDPThreadLocalStorage;
}
UdpNetworkedPhysicsProcessor::UdpNetworkedPhysicsProcessor(const char* hostName, int port)
{
m_data = new UdpNetworkedInternalData;
if (hostName)
{
m_data->m_hostName = hostName;
}
m_data->m_port = port;
}
UdpNetworkedPhysicsProcessor::~UdpNetworkedPhysicsProcessor()
{
disconnect();
delete m_data;
}
bool UdpNetworkedPhysicsProcessor::processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
{
int sz = sizeof(SharedMemoryCommand);
int timeout = 1024 * 1024 * 1024;
m_data->m_cs->lock();
m_data->m_clientCmd = clientCmd;
m_data->m_hasCommand = true;
m_data->m_cs->unlock();
while (m_data->m_hasCommand && (timeout-- > 0))
{
// b3Clock::usleep(100);
}
#if 0
timeout = 1024 * 1024 * 1024;
bool hasStatus = false;
const SharedMemoryStatus* stat = 0;
while ((!hasStatus) && (timeout-- > 0))
{
hasStatus = receiveStatus(serverStatusOut, bufferServerToClient, bufferSizeInBytes);
b3Clock::usleep(100);
}
return hasStatus;
#endif
return false;
}
bool UdpNetworkedPhysicsProcessor::receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
{
bool hasStatus = false;
if (m_data->m_hasStatus)
{
hasStatus = true;
serverStatusOut = m_data->m_lastStatus;
int numStreamBytes = m_data->m_stream.size();
if (numStreamBytes < bufferSizeInBytes)
{
for (int i = 0; i < numStreamBytes; i++)
{
bufferServerToClient[i] = m_data->m_stream[i];
}
}
else
{
printf("Error: steam buffer overflow\n");
}
m_data->m_cs->lock();
m_data->m_hasStatus = false;
m_data->m_cs->unlock();
}
return hasStatus;
}
void UdpNetworkedPhysicsProcessor::renderScene()
{
}
void UdpNetworkedPhysicsProcessor::physicsDebugDraw(int debugDrawFlags)
{
}
void UdpNetworkedPhysicsProcessor::setGuiHelper(struct GUIHelperInterface* guiHelper)
{
}
bool UdpNetworkedPhysicsProcessor::isConnected() const
{
return m_data->m_isConnected;
}
bool UdpNetworkedPhysicsProcessor::connect()
{
if (m_data->m_threadSupport==0)
{
m_data->m_threadSupport = createUDPThreadSupport(1);
m_data->m_cs = m_data->m_threadSupport->createCriticalSection();
m_data->m_cs->setSharedParam(0, eUDPIsUnInitialized);
m_data->m_threadSupport->runTask(B3_THREAD_SCHEDULE_TASK, (void*) m_data, 0);
while (m_data->m_cs->getSharedParam(0) == eUDPIsUnInitialized)
{
b3Clock::usleep(1000);
}
m_data->m_cs->lock();
m_data->m_cs->setSharedParam(1, eUDP_ConnectRequest);
m_data->m_cs->unlock();
while (m_data->m_cs->getSharedParam(1) == eUDP_ConnectRequest)
{
b3Clock::usleep(1000);
}
}
return true;
}
void UdpNetworkedPhysicsProcessor::disconnect()
{
if (m_data->m_threadSupport)
{
m_data->m_cs->lock();
m_data->m_cs->setSharedParam(0, eUDPRequestTerminate);
m_data->m_cs->unlock();
int numActiveThreads = 1;
while (numActiveThreads)
{
int arg0, arg1;
if (m_data->m_threadSupport->isTaskCompleted(&arg0, &arg1, 0))
{
numActiveThreads--;
printf("numActiveThreads = %d\n", numActiveThreads);
}
else
{
b3Clock::usleep(1000);
}
};
printf("stopping threads\n");
delete m_data->m_threadSupport;
m_data->m_threadSupport = 0;
}
}

View File

@@ -0,0 +1,37 @@
#ifndef PHYSICS_CLIENT_UDP_H
#define PHYSICS_CLIENT_UDP_H
#include "PhysicsDirect.h"
#include "PhysicsServerCommandProcessor.h"
class UdpNetworkedPhysicsProcessor : public PhysicsCommandProcessorInterface
{
struct UdpNetworkedInternalData* m_data;
public:
UdpNetworkedPhysicsProcessor(const char* hostName, int port);
virtual ~UdpNetworkedPhysicsProcessor();
virtual bool connect();
virtual void disconnect();
virtual bool isConnected() const;
virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
virtual void renderScene();
virtual void physicsDebugDraw(int debugDrawFlags);
virtual void setGuiHelper(struct GUIHelperInterface* guiHelper);
};
#endif //PHYSICS_CLIENT_UDP_H

View File

@@ -0,0 +1,21 @@
#include "PhysicsClientUDP_C_API.h"
#include "PhysicsClientUDP.h"
#include "PhysicsDirect.h"
#include <stdio.h>
//think more about naming. The b3ConnectPhysicsLoopback
b3PhysicsClientHandle b3ConnectPhysicsUDP(const char* hostName, int port)
{
UdpNetworkedPhysicsProcessor* udp = new UdpNetworkedPhysicsProcessor(hostName, port);
PhysicsDirect* direct = new PhysicsDirect(udp);
bool connected = direct->connect();
printf("direct!\n");
return (b3PhysicsClientHandle)direct;
}

View File

@@ -0,0 +1,19 @@
#ifndef PHYSICS_CLIENT_UDP_C_API_H
#define PHYSICS_CLIENT_UDP_C_API_H
#include "PhysicsClientC_API.h"
#ifdef __cplusplus
extern "C" {
#endif
///send physics commands using UDP networking
b3PhysicsClientHandle b3ConnectPhysicsUDP(const char* hostName, int port);
#ifdef __cplusplus
}
#endif
#endif //PHYSICS_CLIENT_UDP_C_API_H

View File

@@ -0,0 +1,27 @@
#ifndef PHYSICS_COMMAND_PROCESSOR_INTERFACE_H
#define PHYSICS_COMMAND_PROCESSOR_INTERFACE_H
class PhysicsCommandProcessorInterface
{
public:
virtual ~PhysicsCommandProcessorInterface() {}
virtual bool connect()=0;
virtual void disconnect() = 0;
virtual bool isConnected() const = 0;
virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) = 0;
virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) = 0;
virtual void renderScene() = 0;
virtual void physicsDebugDraw(int debugDrawFlags) = 0;
virtual void setGuiHelper(struct GUIHelperInterface* guiHelper) = 0;
};
#endif //PHYSICS_COMMAND_PROCESSOR_INTERFACE_H

View File

@@ -3,7 +3,9 @@
#include "PhysicsClientSharedMemory.h"
#include "../CommonInterfaces/CommonGUIHelperInterface.h"
#include "SharedMemoryCommands.h"
#include "PhysicsServerCommandProcessor.h"
#include "PhysicsCommandProcessorInterface.h"
#include "LinearMath/btHashMap.h"
#include "LinearMath/btAlignedObjectArray.h"
#include "../../Extras/Serialize/BulletFileLoader/btBulletFile.h"
@@ -44,26 +46,34 @@ struct PhysicsDirectInternalData
btAlignedObjectArray<b3VisualShapeData> m_cachedVisualShapes;
PhysicsServerCommandProcessor* m_commandProcessor;
PhysicsCommandProcessorInterface* m_commandProcessor;
bool m_ownsCommandProcessor;
PhysicsDirectInternalData()
:m_hasStatus(false),
m_verboseOutput(false)
m_verboseOutput(false),
m_ownsCommandProcessor(false)
{
}
};
PhysicsDirect::PhysicsDirect()
PhysicsDirect::PhysicsDirect(PhysicsCommandProcessorInterface* physSdk)
{
m_data = new PhysicsDirectInternalData;
m_data->m_commandProcessor = new PhysicsServerCommandProcessor;
m_data->m_commandProcessor = physSdk;
m_data->m_ownsCommandProcessor = false;
}
PhysicsDirect::~PhysicsDirect()
{
delete m_data->m_commandProcessor;
if (m_data->m_commandProcessor->isConnected())
{
m_data->m_commandProcessor->disconnect();
}
if (m_data->m_ownsCommandProcessor)
{
delete m_data->m_commandProcessor;
}
delete m_data;
}
@@ -71,23 +81,26 @@ PhysicsDirect::~PhysicsDirect()
// return true if connection succesfull, can also check 'isConnected'
bool PhysicsDirect::connect()
{
bool connected = m_data->m_commandProcessor->connect();
m_data->m_commandProcessor->setGuiHelper(&m_data->m_noGfx);
return true;
return connected;
}
// return true if connection succesfull, can also check 'isConnected'
bool PhysicsDirect::connect(struct GUIHelperInterface* guiHelper)
{
bool connected = m_data->m_commandProcessor->connect();
m_data->m_commandProcessor->setGuiHelper(guiHelper);
return true;
return connected;
}
void PhysicsDirect::renderScene()
{
m_data->m_commandProcessor->renderScene();
}
void PhysicsDirect::debugDraw(int debugDrawMode)
{
m_data->m_commandProcessor->physicsDebugDraw(debugDrawMode);
@@ -96,21 +109,31 @@ void PhysicsDirect::debugDraw(int debugDrawMode)
////todo: rename to 'disconnect'
void PhysicsDirect::disconnectSharedMemory()
{
m_data->m_commandProcessor->disconnect();
m_data->m_commandProcessor->setGuiHelper(0);
}
bool PhysicsDirect::isConnected() const
{
return true;
return m_data->m_commandProcessor->isConnected();
}
// return non-null if there is a status, nullptr otherwise
const SharedMemoryStatus* PhysicsDirect::processServerStatus()
{
if (!m_data->m_hasStatus)
{
m_data->m_hasStatus = m_data->m_commandProcessor->receiveStatus(m_data->m_serverStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
}
SharedMemoryStatus* stat = 0;
if (m_data->m_hasStatus)
{
stat = &m_data->m_serverStatus;
postProcessStatus(m_data->m_serverStatus);
m_data->m_hasStatus = false;
}
return stat;
@@ -136,7 +159,19 @@ bool PhysicsDirect::processDebugLines(const struct SharedMemoryCommand& orgComma
{
bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
int timeout = 1024 * 1024 * 1024;
while ((!hasStatus) && (timeout-- > 0))
{
const SharedMemoryStatus* stat = processServerStatus();
if (stat)
{
hasStatus = true;
}
}
m_data->m_hasStatus = hasStatus;
if (hasStatus)
{
btAssert(m_data->m_serverStatus.m_type == CMD_DEBUG_LINES_COMPLETED);
@@ -184,6 +219,8 @@ bool PhysicsDirect::processDebugLines(const struct SharedMemoryCommand& orgComma
if (serverCmd.m_sendDebugLinesArgs.m_numRemainingDebugLines > 0)
{
m_data->m_hasStatus = false;
command.m_type = CMD_REQUEST_DEBUG_LINES;
command.m_requestDebugLinesArguments.m_startingLineIndex =
serverCmd.m_sendDebugLinesArgs.m_numDebugLines +
@@ -204,6 +241,17 @@ bool PhysicsDirect::processVisualShapeData(const struct SharedMemoryCommand& org
do
{
bool hasStatus = m_data->m_commandProcessor->processCommand(command, m_data->m_serverStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
int timeout = 1024 * 1024 * 1024;
while ((!hasStatus) && (timeout-- > 0))
{
const SharedMemoryStatus* stat = processServerStatus();
if (stat)
{
hasStatus = true;
}
}
m_data->m_hasStatus = hasStatus;
if (hasStatus)
{
@@ -223,6 +271,8 @@ bool PhysicsDirect::processVisualShapeData(const struct SharedMemoryCommand& org
if (serverCmd.m_sendVisualShapeArgs.m_numRemainingVisualShapes >0 && serverCmd.m_sendVisualShapeArgs.m_numVisualShapesCopied)
{
m_data->m_hasStatus = false;
command.m_type = CMD_REQUEST_VISUAL_SHAPE_INFO;
command.m_requestVisualShapeDataArguments.m_startingVisualShapeIndex = serverCmd.m_sendVisualShapeArgs.m_startingVisualShapeIndex + serverCmd.m_sendVisualShapeArgs.m_numVisualShapesCopied;
command.m_requestVisualShapeDataArguments.m_bodyUniqueId = serverCmd.m_sendVisualShapeArgs.m_bodyUniqueId;
@@ -243,7 +293,19 @@ bool PhysicsDirect::processContactPointData(const struct SharedMemoryCommand& or
do
{
bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
m_data->m_hasStatus = hasStatus;
int timeout = 1024 * 1024 * 1024;
while ((!hasStatus) && (timeout-- > 0))
{
const SharedMemoryStatus* stat = processServerStatus();
if (stat)
{
hasStatus = true;
}
}
m_data->m_hasStatus = hasStatus;
if (hasStatus)
{
if (m_data->m_verboseOutput)
@@ -264,7 +326,10 @@ bool PhysicsDirect::processContactPointData(const struct SharedMemoryCommand& or
if (serverCmd.m_sendContactPointArgs.m_numRemainingContactPoints>0 && serverCmd.m_sendContactPointArgs.m_numContactPointsCopied)
{
command.m_type = CMD_REQUEST_CONTACT_POINT_INFORMATION;
m_data->m_hasStatus = false;
command.m_type = CMD_REQUEST_CONTACT_POINT_INFORMATION;
command.m_requestContactPointArguments.m_startingContactPointIndex = serverCmd.m_sendContactPointArgs.m_startingContactPointIndex+serverCmd.m_sendContactPointArgs.m_numContactPointsCopied;
command.m_requestContactPointArguments.m_objectAIndexFilter = -1;
command.m_requestContactPointArguments.m_objectBIndexFilter = -1;
@@ -289,6 +354,18 @@ bool PhysicsDirect::processCamera(const struct SharedMemoryCommand& orgCommand)
{
bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
int timeout = 1024 * 1024 * 1024;
while ((!hasStatus) && (timeout-- > 0))
{
const SharedMemoryStatus* stat = processServerStatus();
if (stat)
{
hasStatus = true;
}
}
m_data->m_hasStatus = hasStatus;
if (hasStatus)
{
@@ -340,6 +417,7 @@ bool PhysicsDirect::processCamera(const struct SharedMemoryCommand& orgCommand)
if (serverCmd.m_sendPixelDataArguments.m_numRemainingPixels > 0 && serverCmd.m_sendPixelDataArguments.m_numPixelsCopied)
{
m_data->m_hasStatus = false;
// continue requesting remaining pixels
command.m_type = CMD_REQUEST_CAMERA_IMAGE_DATA;
@@ -365,7 +443,7 @@ void PhysicsDirect::processBodyJointInfo(int bodyUniqueId, const SharedMemorySta
{
bParse::btBulletFile bf(
&m_data->m_bulletStreamDataServerToClient[0],
serverCmd.m_dataStreamArguments.m_streamChunkLength);
serverCmd.m_numDataStreamBytes);
bf.setFileDNAisMemoryDNA();
bf.parse(false);
@@ -402,6 +480,87 @@ void PhysicsDirect::processBodyJointInfo(int bodyUniqueId, const SharedMemorySta
}
}
void PhysicsDirect::postProcessStatus(const struct SharedMemoryStatus& serverCmd)
{
switch (serverCmd.m_type)
{
case CMD_RESET_SIMULATION_COMPLETED:
{
m_data->m_debugLinesFrom.clear();
m_data->m_debugLinesTo.clear();
m_data->m_debugLinesColor.clear();
for (int i = 0; i<m_data->m_bodyJointMap.size(); i++)
{
BodyJointInfoCache2** bodyJointsPtr = m_data->m_bodyJointMap.getAtIndex(i);
if (bodyJointsPtr && *bodyJointsPtr)
{
BodyJointInfoCache2* bodyJoints = *bodyJointsPtr;
for (int j = 0; j<bodyJoints->m_jointInfo.size(); j++) {
if (bodyJoints->m_jointInfo[j].m_jointName)
{
free(bodyJoints->m_jointInfo[j].m_jointName);
}
if (bodyJoints->m_jointInfo[j].m_linkName)
{
free(bodyJoints->m_jointInfo[j].m_linkName);
}
}
delete (*bodyJointsPtr);
}
}
m_data->m_bodyJointMap.clear();
break;
}
case CMD_SDF_LOADING_COMPLETED:
{
//we'll stream further info from the physics server
//so serverCmd will be invalid, make a copy
int numBodies = serverCmd.m_sdfLoadedArgs.m_numBodies;
for (int i = 0; i<numBodies; i++)
{
int bodyUniqueId = serverCmd.m_sdfLoadedArgs.m_bodyUniqueIds[i];
SharedMemoryCommand infoRequestCommand;
infoRequestCommand.m_type = CMD_REQUEST_BODY_INFO;
infoRequestCommand.m_sdfRequestInfoArgs.m_bodyUniqueId = bodyUniqueId;
SharedMemoryStatus infoStatus;
bool hasStatus = m_data->m_commandProcessor->processCommand(infoRequestCommand, infoStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
int timeout = 1024 * 1024 * 1024;
while ((!hasStatus) && (timeout-- > 0))
{
hasStatus = m_data->m_commandProcessor->receiveStatus(infoStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
}
if (hasStatus)
{
processBodyJointInfo(bodyUniqueId, infoStatus);
}
}
break;
}
case CMD_URDF_LOADING_COMPLETED:
{
if (serverCmd.m_numDataStreamBytes > 0)
{
int bodyIndex = serverCmd.m_dataStreamArguments.m_bodyUniqueId;
processBodyJointInfo(bodyIndex, serverCmd);
}
break;
}
default:
{
// b3Error("Unknown server status type");
}
};
}
bool PhysicsDirect::submitClientCommand(const struct SharedMemoryCommand& command)
{
if (command.m_type==CMD_REQUEST_DEBUG_LINES)
@@ -427,78 +586,7 @@ bool PhysicsDirect::submitClientCommand(const struct SharedMemoryCommand& comman
m_data->m_hasStatus = hasStatus;
if (hasStatus)
{
const SharedMemoryStatus& serverCmd = m_data->m_serverStatus;
switch (m_data->m_serverStatus.m_type)
{
case CMD_RESET_SIMULATION_COMPLETED:
{
m_data->m_debugLinesFrom.clear();
m_data->m_debugLinesTo.clear();
m_data->m_debugLinesColor.clear();
for (int i=0;i<m_data->m_bodyJointMap.size();i++)
{
BodyJointInfoCache2** bodyJointsPtr = m_data->m_bodyJointMap.getAtIndex(i);
if (bodyJointsPtr && *bodyJointsPtr)
{
BodyJointInfoCache2* bodyJoints = *bodyJointsPtr;
for (int j=0;j<bodyJoints->m_jointInfo.size();j++) {
if (bodyJoints->m_jointInfo[j].m_jointName)
{
free(bodyJoints->m_jointInfo[j].m_jointName);
}
if (bodyJoints->m_jointInfo[j].m_linkName)
{
free(bodyJoints->m_jointInfo[j].m_linkName);
}
}
delete (*bodyJointsPtr);
}
}
m_data->m_bodyJointMap.clear();
break;
}
case CMD_SDF_LOADING_COMPLETED:
{
//we'll stream further info from the physics server
//so serverCmd will be invalid, make a copy
int numBodies = serverCmd.m_sdfLoadedArgs.m_numBodies;
for (int i=0;i<numBodies;i++)
{
int bodyUniqueId = serverCmd.m_sdfLoadedArgs.m_bodyUniqueIds[i];
SharedMemoryCommand infoRequestCommand;
infoRequestCommand.m_type = CMD_REQUEST_BODY_INFO;
infoRequestCommand.m_sdfRequestInfoArgs.m_bodyUniqueId = bodyUniqueId;
SharedMemoryStatus infoStatus;
bool hasStatus = m_data->m_commandProcessor->processCommand(infoRequestCommand,infoStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
if (hasStatus)
{
processBodyJointInfo(bodyUniqueId, infoStatus);
}
}
break;
}
case CMD_URDF_LOADING_COMPLETED:
{
if (serverCmd.m_dataStreamArguments.m_streamChunkLength > 0)
{
int bodyIndex = serverCmd.m_dataStreamArguments.m_bodyUniqueId;
processBodyJointInfo(bodyIndex,serverCmd);
}
break;
}
default:
{
// b3Error("Unknown server status type");
}
};
postProcessStatus(m_data->m_serverStatus);
}
return hasStatus;
}
@@ -549,7 +637,7 @@ bool PhysicsDirect::getJointInfo(int bodyIndex, int jointIndex, struct b3JointIn
if (bodyJointsPtr && *bodyJointsPtr)
{
BodyJointInfoCache2* bodyJoints = *bodyJointsPtr;
if (jointIndex < bodyJoints->m_jointInfo.size())
if ((jointIndex >=0) && (jointIndex < bodyJoints->m_jointInfo.size()))
{
info = bodyJoints->m_jointInfo[jointIndex];
return true;

View File

@@ -7,9 +7,6 @@
#include "PhysicsClient.h"
#include "LinearMath/btVector3.h"
///todo: the PhysicsClient API was designed with shared memory in mind,
///now it become more general we need to move out the shared memory specifics away
///for example naming [disconnectSharedMemory -> disconnect] [ move setSharedMemoryKey to shared memory specific subclass ]
///PhysicsDirect executes the commands directly, without transporting them or having a separate server executing commands
class PhysicsDirect : public PhysicsClient
{
@@ -27,9 +24,11 @@ protected:
void processBodyJointInfo(int bodyUniqueId, const struct SharedMemoryStatus& serverCmd);
void postProcessStatus(const struct SharedMemoryStatus& serverCmd);
public:
PhysicsDirect();
PhysicsDirect(class PhysicsCommandProcessorInterface* physSdk);
virtual ~PhysicsDirect();

View File

@@ -2,13 +2,21 @@
#include "PhysicsDirect.h"
#include "PhysicsServerCommandProcessor.h"
//think more about naming. The b3ConnectPhysicsLoopback
b3PhysicsClientHandle b3ConnectPhysicsDirect()
{
PhysicsDirect* direct = new PhysicsDirect();
PhysicsServerCommandProcessor* sdk = new PhysicsServerCommandProcessor;
PhysicsDirect* direct = new PhysicsDirect(sdk);
bool connected = direct->connect();
return (b3PhysicsClientHandle )direct;
}
//

View File

@@ -1187,6 +1187,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
//catch uninitialized cases
serverStatusOut.m_type = CMD_INVALID_STATUS;
serverStatusOut.m_numDataStreamBytes = 0;
serverStatusOut.m_dataStream = 0;
//consume the command
switch (clientCmd.m_type)
@@ -1244,7 +1246,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
}
//9 floats per line: 3 floats for 'from', 3 floats for 'to' and 3 floats for 'color'
int maxNumLines = bufferSizeInBytes/(sizeof(float)*9)-1;
int bytesPerLine = (sizeof(float) * 9);
int maxNumLines = bufferSizeInBytes/bytesPerLine-1;
if (startingLineIndex >m_data->m_remoteDebugDrawer->m_lines2.size())
{
b3Warning("m_startingLineIndex exceeds total number of debug lines");
@@ -1277,7 +1280,7 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
}
serverStatusOut.m_type = CMD_DEBUG_LINES_COMPLETED;
serverStatusOut.m_numDataStreamBytes = numLines * bytesPerLine;
serverStatusOut.m_sendDebugLinesArgs.m_numDebugLines = numLines;
serverStatusOut.m_sendDebugLinesArgs.m_startingLineIndex = startingLineIndex;
serverStatusOut.m_sendDebugLinesArgs.m_numRemainingDebugLines = m_data->m_remoteDebugDrawer->m_lines2.size()-(startingLineIndex+numLines);
@@ -1327,6 +1330,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
float* depthBuffer = (float*)(bufferServerToClient+numRequestedPixels*4);
int* segmentationMaskBuffer = (int*)(bufferServerToClient+numRequestedPixels*8);
serverStatusOut.m_numDataStreamBytes = numRequestedPixels * totalBytesPerPixel;
if ((clientCmd.m_updateFlags & ER_BULLET_HARDWARE_OPENGL)!=0)
{
m_data->m_guiHelper->copyCameraImageData(clientCmd.m_requestPixelDataArguments.m_viewMatrix,
@@ -1368,6 +1373,7 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
}
serverStatusOut.m_type = CMD_CAMERA_IMAGE_COMPLETED;
serverStatusOut.m_sendPixelDataArguments.m_numPixelsCopied = numPixelsCopied;
serverStatusOut.m_sendPixelDataArguments.m_numRemainingPixels = numRemainingPixels - numPixelsCopied;
serverStatusOut.m_sendPixelDataArguments.m_startingPixelIndex = startPixelIndex;
@@ -1386,7 +1392,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
serverStatusOut.m_type = CMD_BODY_INFO_COMPLETED;
serverStatusOut.m_dataStreamArguments.m_bodyUniqueId = sdfInfoArgs.m_bodyUniqueId;
serverStatusOut.m_dataStreamArguments.m_streamChunkLength = streamSizeInBytes;
serverStatusOut.m_numDataStreamBytes = streamSizeInBytes;
hasStatus = true;
break;
}
@@ -1606,11 +1613,11 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
m_data->m_guiHelper->autogenerateGraphicsObjects(this->m_data->m_dynamicsWorld);
serverStatusOut.m_type = CMD_URDF_LOADING_COMPLETED;
serverStatusOut.m_dataStreamArguments.m_streamChunkLength = 0;
if (m_data->m_urdfLinkNameMapper.size())
{
serverStatusOut.m_dataStreamArguments.m_streamChunkLength = m_data->m_urdfLinkNameMapper.at(m_data->m_urdfLinkNameMapper.size()-1)->m_memSerializer->getCurrentBufferSize();
serverStatusOut.m_numDataStreamBytes = m_data->m_urdfLinkNameMapper.at(m_data->m_urdfLinkNameMapper.size()-1)->m_memSerializer->getCurrentBufferSize();
}
serverStatusOut.m_dataStreamArguments.m_bodyUniqueId = bodyUniqueId;
hasStatus = true;
@@ -2583,7 +2590,7 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
serverCmd.m_sendContactPointArgs.m_startingContactPointIndex = clientCmd.m_requestContactPointArguments.m_startingContactPointIndex;
serverCmd.m_sendContactPointArgs.m_numRemainingContactPoints = numContactPoints - clientCmd.m_requestContactPointArguments.m_startingContactPointIndex - serverCmd.m_sendContactPointArgs.m_numContactPointsCopied;
serverCmd.m_numDataStreamBytes = totalBytesPerContact * serverCmd.m_sendContactPointArgs.m_numContactPointsCopied;
serverCmd.m_type = CMD_CONTACT_POINT_INFORMATION_COMPLETED; //CMD_CONTACT_POINT_INFORMATION_FAILED,
hasStatus = true;
break;
@@ -3006,7 +3013,7 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm
serverCmd.m_sendVisualShapeArgs.m_numVisualShapesCopied = 1;
serverCmd.m_sendVisualShapeArgs.m_startingVisualShapeIndex = clientCmd.m_requestVisualShapeDataArguments.m_startingVisualShapeIndex;
serverCmd.m_sendVisualShapeArgs.m_bodyUniqueId = clientCmd.m_requestVisualShapeDataArguments.m_bodyUniqueId;
serverCmd.m_numDataStreamBytes = sizeof(b3VisualShapeData)*serverCmd.m_sendVisualShapeArgs.m_numVisualShapesCopied;
serverCmd.m_type =CMD_VISUAL_SHAPE_INFO_COMPLETED;
hasStatus = true;
break;

View File

@@ -3,6 +3,8 @@
#include "LinearMath/btVector3.h"
#include "PhysicsCommandProcessorInterface.h"
struct SharedMemLines
{
btVector3 m_from;
@@ -10,8 +12,10 @@ struct SharedMemLines
btVector3 m_color;
};
///todo: naming. Perhaps PhysicsSdkCommandprocessor?
class PhysicsServerCommandProcessor
class PhysicsServerCommandProcessor : public PhysicsCommandProcessorInterface
{
struct PhysicsServerCommandProcessorInternalData* m_data;
@@ -24,10 +28,10 @@ protected:
bool loadSdf(const char* fileName, char* bufferServerToClient, int bufferSizeInBytes, bool useMultiBody);
bool loadSdf(const char* fileName, char* bufferServerToClient, int bufferSizeInBytes, bool useMultiBody);
bool loadUrdf(const char* fileName, const class btVector3& pos, const class btQuaternion& orn,
bool useMultiBody, bool useFixedBase, int* bodyUniqueIdPtr, char* bufferServerToClient, int bufferSizeInBytes);
bool useMultiBody, bool useFixedBase, int* bodyUniqueIdPtr, char* bufferServerToClient, int bufferSizeInBytes);
bool supportsJointMotor(class btMultiBody* body, int linkIndex);
@@ -43,8 +47,26 @@ public:
virtual void createEmptyDynamicsWorld();
virtual void deleteDynamicsWorld();
virtual bool connect()
{
return true;
};
virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes );
virtual void disconnect() {}
virtual bool isConnected() const
{
return true;
}
virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
{
return false;
};
virtual void renderScene();
virtual void physicsDebugDraw(int debugDrawFlags);

View File

@@ -0,0 +1,216 @@
#include "SharedMemoryCommandProcessor.h"
#include "PosixSharedMemory.h"
#include "Win32SharedMemory.h"
#include "Bullet3Common/b3Logging.h"
#include "Bullet3Common/b3Scalar.h"
#include "SharedMemoryBlock.h"
struct SharedMemoryCommandProcessorInternalData
{
int m_sharedMemoryKey;
bool m_isConnected;
SharedMemoryInterface* m_sharedMemory;
bool m_ownsSharedMemory;
bool m_verboseOutput;
bool m_waitingForServer;
SharedMemoryStatus m_lastServerStatus;
SharedMemoryBlock* m_testBlock1;
SharedMemoryCommandProcessorInternalData()
:m_sharedMemoryKey(SHARED_MEMORY_KEY),
m_isConnected(false),
m_sharedMemory(0),
m_ownsSharedMemory(false),
m_verboseOutput(false),
m_waitingForServer(false),
m_testBlock1(0)
{
}
};
SharedMemoryCommandProcessor::SharedMemoryCommandProcessor()
{
m_data = new SharedMemoryCommandProcessorInternalData;
m_data->m_sharedMemoryKey = SHARED_MEMORY_KEY;
#ifdef _WIN32
m_data->m_sharedMemory = new Win32SharedMemoryClient();
#else
m_data->m_sharedMemory = new PosixSharedMemory();
#endif
m_data->m_ownsSharedMemory = true;
}
SharedMemoryCommandProcessor::~SharedMemoryCommandProcessor()
{
if (m_data->m_isConnected)
{
disconnect();
}
if (m_data->m_ownsSharedMemory)
{
delete m_data->m_sharedMemory;
}
delete m_data;
}
bool SharedMemoryCommandProcessor::connect()
{
if (m_data->m_isConnected)
return true;
bool allowCreation = false;
m_data->m_testBlock1 = (SharedMemoryBlock*)m_data->m_sharedMemory->allocateSharedMemory(
m_data->m_sharedMemoryKey, SHARED_MEMORY_SIZE, allowCreation);
if (m_data->m_testBlock1) {
if (m_data->m_testBlock1->m_magicId != SHARED_MEMORY_MAGIC_NUMBER) {
b3Error("Error: please start server before client\n");
m_data->m_sharedMemory->releaseSharedMemory(m_data->m_sharedMemoryKey,
SHARED_MEMORY_SIZE);
m_data->m_testBlock1 = 0;
return false;
}
else {
if (m_data->m_verboseOutput) {
b3Printf("Connected to existing shared memory, status OK.\n");
}
m_data->m_isConnected = true;
}
}
else {
b3Error("Cannot connect to shared memory");
return false;
}
return true;
}
void SharedMemoryCommandProcessor::disconnect()
{
if (m_data->m_isConnected && m_data->m_sharedMemory)
{
m_data->m_sharedMemory->releaseSharedMemory(m_data->m_sharedMemoryKey, SHARED_MEMORY_SIZE);
}
m_data->m_isConnected = false;
}
bool SharedMemoryCommandProcessor::isConnected() const
{
return m_data->m_isConnected;
}
bool SharedMemoryCommandProcessor::processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
{
if (!m_data->m_waitingForServer) {
if (&m_data->m_testBlock1->m_clientCommands[0] != &clientCmd) {
m_data->m_testBlock1->m_clientCommands[0] = clientCmd;
}
m_data->m_testBlock1->m_numClientCommands++;
m_data->m_waitingForServer = true;
}
return false;
}
bool SharedMemoryCommandProcessor::receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
{
SharedMemoryStatus* stat = 0;
m_data->m_lastServerStatus.m_dataStream = 0;
m_data->m_lastServerStatus.m_numDataStreamBytes = 0;
if (!m_data->m_testBlock1)
{
//m_data->m_lastServerStatus.m_type = CMD_SHARED_MEMORY_NOT_INITIALIZED;
//return &m_data->m_lastServerStatus;
//serverStatusOut = m_data->m_lastServerStatus;
return false;
}
if (!m_data->m_waitingForServer) {
return false;
}
if (m_data->m_testBlock1->m_magicId != SHARED_MEMORY_MAGIC_NUMBER)
{
//m_data->m_lastServerStatus.m_type = CMD_SHARED_MEMORY_NOT_INITIALIZED;
//return &m_data->m_lastServerStatus;
return false;
}
if (m_data->m_testBlock1->m_numServerCommands >
m_data->m_testBlock1->m_numProcessedServerCommands)
{
b3Assert(m_data->m_testBlock1->m_numServerCommands ==
m_data->m_testBlock1->m_numProcessedServerCommands + 1);
const SharedMemoryStatus& serverCmd = m_data->m_testBlock1->m_serverCommands[0];
m_data->m_lastServerStatus = serverCmd;
m_data->m_lastServerStatus.m_dataStream = m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor;
for (int i = 0; i < m_data->m_lastServerStatus.m_numDataStreamBytes; i++)
{
bufferServerToClient[i] = m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor[i];
}
m_data->m_testBlock1->m_numProcessedServerCommands++;
// we don't have more than 1 command outstanding (in total, either server or client)
b3Assert(m_data->m_testBlock1->m_numProcessedServerCommands ==
m_data->m_testBlock1->m_numServerCommands);
if (m_data->m_testBlock1->m_numServerCommands ==
m_data->m_testBlock1->m_numProcessedServerCommands) {
m_data->m_waitingForServer = false;
}
else {
m_data->m_waitingForServer = true;
}
serverStatusOut = m_data->m_lastServerStatus;
return true;
}
return false;
}
void SharedMemoryCommandProcessor::renderScene()
{
}
void SharedMemoryCommandProcessor::physicsDebugDraw(int debugDrawFlags)
{
}
void SharedMemoryCommandProcessor::setGuiHelper(struct GUIHelperInterface* guiHelper)
{
}
void SharedMemoryCommandProcessor::setSharedMemoryInterface(class SharedMemoryInterface* sharedMem)
{
if (m_data->m_sharedMemory && m_data->m_ownsSharedMemory)
{
delete m_data->m_sharedMemory;
}
m_data->m_ownsSharedMemory = false;
m_data->m_sharedMemory = sharedMem;
}
void SharedMemoryCommandProcessor::setSharedMemoryKey(int key)
{
m_data->m_sharedMemoryKey = key;
}

View File

@@ -0,0 +1,37 @@
#ifndef SHARED_MEMORY_COMMAND_PROCESSOR_H
#define SHARED_MEMORY_COMMAND_PROCESSOR_H
#include "PhysicsCommandProcessorInterface.h"
class SharedMemoryCommandProcessor : public PhysicsCommandProcessorInterface
{
struct SharedMemoryCommandProcessorInternalData* m_data;
public:
SharedMemoryCommandProcessor();
virtual ~SharedMemoryCommandProcessor();
virtual bool connect();
virtual void disconnect();
virtual bool isConnected() const;
virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
virtual void renderScene();
virtual void physicsDebugDraw(int debugDrawFlags);
virtual void setGuiHelper(struct GUIHelperInterface* guiHelper);
void setSharedMemoryInterface(class SharedMemoryInterface* sharedMem);
void setSharedMemoryKey(int key);
};
#endif //SHARED_MEMORY_COMMAND_PROCESSOR_H

View File

@@ -90,7 +90,6 @@ struct UrdfArgs
struct BulletDataStreamArgs
{
char m_bulletFileName[MAX_FILENAME_LENGTH];
int m_streamChunkLength;
int m_bodyUniqueId;
};
@@ -508,6 +507,10 @@ struct SharedMemoryStatus
smUint64_t m_timeStamp;
int m_sequenceNumber;
//m_streamBytes is only for internal purposes
int m_numDataStreamBytes;
char* m_dataStream;
union
{
struct BulletDataStreamArgs m_dataStreamArguments;

View File

@@ -42,6 +42,14 @@ myfiles =
"PhysicsLoopBack.h",
"PhysicsLoopBackC_API.cpp",
"PhysicsLoopBackC_API.h",
"PhysicsClientSharedMemory_C_API.cpp",
"PhysicsClientSharedMemory_C_API.h",
"PhysicsClientSharedMemory2_C_API.cpp",
"PhysicsClientSharedMemory2_C_API.h",
"PhysicsClientSharedMemory2.cpp",
"PhysicsClientSharedMemory2.h",
"SharedMemoryCommandProcessor.cpp",
"SharedMemoryCommandProcessor.h",
"PhysicsServerCommandProcessor.cpp",
"PhysicsServerCommandProcessor.h",
"TinyRendererVisualShapeConverter.cpp",
@@ -289,3 +297,6 @@ if os.is("Windows") then
end
include "udp"

View File

@@ -0,0 +1,187 @@
/* server.cpp */
#include <stdio.h>
#include <enet/enet.h>
#include "SharedMemoryCommandProcessor.h"
#include "SharedMemoryCommands.h"
#include "Bullet3Common/b3AlignedObjectArray.h"
#include "PhysicsServerCommandProcessor.h"
void MySerializeInt(unsigned int sz, unsigned char* output)
{
unsigned int tmp = sz;
output[0] = tmp & 255;
tmp = tmp >> 8;
output[1] = tmp & 255;
tmp = tmp >> 8;
output[2] = tmp & 255;
tmp = tmp >> 8;
output[3] = tmp & 255;
}
int main(int argc, char *argv[])
{
unsigned char buf[4];
SharedMemoryCommandProcessor* sm = new SharedMemoryCommandProcessor;
// PhysicsDirect* sm = new PhysicsDirect(sdk);
//PhysicsClientSharedMemory* sm = new PhysicsClientSharedMemory();
bool isPhysicsClientConnected = sm->connect();
if (isPhysicsClientConnected)
{
ENetAddress address;
ENetHost *server;
ENetEvent event;
int serviceResult;
puts("Starting server");
if (enet_initialize() != 0)
{
puts("Error initialising enet");
exit(EXIT_FAILURE);
}
/* Bind the server to the default localhost. */
/* A specific host address can be specified by */
/* enet_address_set_host (& address, "x.x.x.x"); */
address.host = ENET_HOST_ANY;
/* Bind the server to port 1234. */
address.port = 1234;
server = enet_host_create(&address,
32, /* number of clients */
2, /* number of channels */
0, /* Any incoming bandwith */
0); /* Any outgoing bandwith */
if (server == NULL)
{
puts("Could not create server host");
exit(EXIT_FAILURE);
}
while (true)
{
serviceResult = 1;
/* Keep doing host_service until no events are left */
while (serviceResult > 0)
{
/* Wait up to 1000 milliseconds for an event. */
serviceResult = enet_host_service(server, &event, 0);
if (serviceResult > 0)
{
switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT:
printf("A new client connected from %x:%u.\n",
event.peer->address.host,
event.peer->address.port);
/* Store any relevant client information here. */
event.peer->data = (void*)"Client information";
break;
case ENET_EVENT_TYPE_RECEIVE:
printf("A packet of length %u containing '%s' was "
"received from %s on channel %u.\n",
event.packet->dataLength,
event.packet->data,
event.peer->data,
event.channelID);
if (event.packet->dataLength == sizeof(SharedMemoryCommand))
{
SharedMemoryCommand* cmdPtr = (SharedMemoryCommand*)event.packet->data;
SharedMemoryStatus serverStatus;
b3AlignedObjectArray<char> buffer;
buffer.resize(SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
bool hasStatus = sm->processCommand(*cmdPtr,serverStatus, &buffer[0], buffer.size());
int timeout = 1024 * 1024 * 1024;
while ((!hasStatus) && (timeout-- > 0))
{
hasStatus = sm->receiveStatus(serverStatus, &buffer[0], buffer.size());
}
printf("buffer.size = %d\n", buffer.size());
printf("serverStatus.m_numDataStreamBytes = %d\n", serverStatus.m_numDataStreamBytes);
if (hasStatus)
{
//create packetData with [int packetSizeInBytes, status, streamBytes)
unsigned char* statBytes = (unsigned char*)&serverStatus;
b3AlignedObjectArray<unsigned char> packetData;
packetData.resize(4 + sizeof(SharedMemoryStatus) + serverStatus.m_numDataStreamBytes);
int sz = packetData.size();
int curPos = 0;
MySerializeInt(sz, &packetData[curPos]);
curPos += 4;
for (int i = 0; i < sizeof(SharedMemoryStatus); i++)
{
packetData[i + curPos] = statBytes[i];
}
curPos += sizeof(SharedMemoryStatus);
for (int i = 0; i < serverStatus.m_numDataStreamBytes; i++)
{
packetData[i + curPos] = serverStatus.m_dataStream[i];
}
ENetPacket *packet = enet_packet_create(&packetData[0], packetData.size() , ENET_PACKET_FLAG_RELIABLE);
//enet_peer_send(peer, 0, packet);
enet_host_broadcast(server, 0, packet);
}
}
else
{
printf("received packet with unknown contents\n");
}
/* Tell all clients about this message */
//enet_host_broadcast(server, 0, event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
printf("%s disconnected.\n", event.peer->data);
/* Reset the peer's client information. */
event.peer->data = NULL;
break;
}
}
else if (serviceResult > 0)
{
puts("Error with servicing the server");
exit(EXIT_FAILURE);
}
}
}
enet_host_destroy(server);
enet_deinitialize();
}
delete sm;
return 0;
}

View File

@@ -0,0 +1,46 @@
project ("App_PhysicsServerUDP")
language "C++"
kind "ConsoleApp"
includedirs {"../../ThirdPartyLibs/enet/include","../../../src",".."}
if os.is("Windows") then
defines { "WIN32" }
links {"Ws2_32","Winmm"}
end
if os.is("Linux") then
end
if os.is("MacOSX") then
end
links {
"enet",
"BulletFileLoader",
"Bullet3Common",
"LinearMath"
}
files {
"main.cpp",
"../PhysicsClient.cpp",
"../PhysicsClient.h",
"../PhysicsDirect.cpp",
"../PhysicsDirect.h",
"../PhysicsCommandProcessorInterface.h",
"../SharedMemoryCommandProcessor.cpp",
"../SharedMemoryCommandProcessor.h",
"../PhysicsClientC_API.cpp",
"../PhysicsClientC_API.h",
"../Win32SharedMemory.cpp",
"../Win32SharedMemory.h",
"../PosixSharedMemory.cpp",
"../PosixSharedMemory.h",
"../../Utils/b3ResourcePath.cpp",
"../../Utils/b3ResourcePath.h",
}

View File

@@ -844,13 +844,13 @@ void CMainApplication::RenderFrame()
// happen right before and after the vsync causing all kinds of jittering issues. This glFinish()
// appears to clear that up. Temporary fix while I try to get nvidia to investigate this problem.
// 1/29/2014 mikesart
glFinish();
//glFinish();
}
// SwapWindow
{
B3_PROFILE("m_app->swapBuffer");
m_app->swapBuffer();
// m_app->swapBuffer();
//SDL_GL_SwapWindow( m_pWindow );
}

View File

@@ -14,7 +14,6 @@
files{"unix.c"}
end
targetdir "../../../lib"
includedirs {
".","include"

View File

@@ -3,6 +3,7 @@ INCLUDE_DIRECTORIES(
${BULLET_PHYSICS_SOURCE_DIR}/src
${BULLET_PHYSICS_SOURCE_DIR}/examples
${BULLET_PHYSICS_SOURCE_DIR}/examples/ThirdPartyLibs
${BULLET_PHYSICS_SOURCE_DIR}/examples/ThirdPartyLibs/enet/include
${PYTHON_INCLUDE_DIRS}
)
IF(BUILD_PYBULLET_NUMPY)
@@ -16,7 +17,7 @@ SET(pybullet_SRCS
../../examples/SharedMemory/IKTrajectoryHelper.cpp
../../examples/SharedMemory/IKTrajectoryHelper.h
../../examples/ExampleBrowser/InProcessExampleBrowser.cpp
../../examples/SharedMemory/TinyRendererVisualShapeConverter.cpp
../../examples/SharedMemory/TinyRendererVisualShapeConverter.cpp
../../examples/SharedMemory/TinyRendererVisualShapeConverter.h
../../examples/OpenGLWindow/SimpleCamera.cpp
../../examples/OpenGLWindow/SimpleCamera.h
@@ -42,6 +43,9 @@ SET(pybullet_SRCS
../../examples/SharedMemory/PhysicsServerCommandProcessor.h
../../examples/SharedMemory/PhysicsClientSharedMemory.cpp
../../examples/SharedMemory/PhysicsClientSharedMemory.h
../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp
../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.h
../../examples/SharedMemory/PhysicsClientC_API.cpp
../../examples/SharedMemory/PhysicsClientC_API.h
../../examples/SharedMemory/Win32SharedMemory.cpp
@@ -69,20 +73,55 @@ SET(pybullet_SRCS
../../examples/MultiThreading/b3PosixThreadSupport.cpp
../../examples/MultiThreading/b3Win32ThreadSupport.cpp
../../examples/MultiThreading/b3ThreadSupportInterface.cpp
)
IF(WIN32)
LINK_LIBRARIES(
LINK_LIBRARIES(
${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY}
)
IF(BUILD_PYBULLET_ENET)
ADD_DEFINITIONS(-DWIN32 -DBT_ENABLE_ENET)
ENDIF(BUILD_PYBULLET_ENET)
ENDIF(WIN32)
ADD_LIBRARY(pybullet SHARED ${pybullet_SRCS})
IF(BUILD_PYBULLET_ENET)
ADD_LIBRARY(pybullet SHARED ${pybullet_SRCS}
../../examples/SharedMemory/PhysicsClientUDP.cpp
../../examples/SharedMemory/PhysicsClientUDP_C_API.cpp
../../examples/SharedMemory/PhysicsClientUDP.h
../../examples/SharedMemory/PhysicsClientUDP_C_API.h
../../examples/ThirdPartyLibs/enet/win32.c
../../examples/ThirdPartyLibs/enet/unix.c
../../examples/ThirdPartyLibs/enet/callbacks.c
../../examples/ThirdPartyLibs/enet/compress.c
../../examples/ThirdPartyLibs/enet/host.c
../../examples/ThirdPartyLibs/enet/list.c
../../examples/ThirdPartyLibs/enet/packet.c
../../examples/ThirdPartyLibs/enet/peer.c
../../examples/ThirdPartyLibs/enet/protocol.c
)
ELSE(BUILD_PYBULLET_ENET)
ADD_LIBRARY(pybullet SHARED ${pybullet_SRCS})
ENDIF(BUILD_PYBULLET_ENET)
SET_TARGET_PROPERTIES(pybullet PROPERTIES VERSION ${BULLET_VERSION})
SET_TARGET_PROPERTIES(pybullet PROPERTIES SOVERSION ${BULLET_VERSION})
TARGET_LINK_LIBRARIES(pybullet BulletExampleBrowserLib BulletFileLoader BulletWorldImporter BulletSoftBody BulletDynamics BulletCollision BulletInverseDynamicsUtils BulletInverseDynamics LinearMath OpenGLWindow gwen BussIK Bullet3Common ${PYTHON_LIBRARIES})
SET_TARGET_PROPERTIES(pybullet PROPERTIES DEBUG_POSTFIX "_d")
IF(WIN32)
IF(BUILD_PYBULLET_ENET)
TARGET_LINK_LIBRARIES(pybullet ws2_32 )
ENDIF(BUILD_PYBULLET_ENET)
SET_TARGET_PROPERTIES(pybullet PROPERTIES SUFFIX ".pyd" )
ENDIF(WIN32)
TARGET_LINK_LIBRARIES(pybullet ws2_32 BulletExampleBrowserLib BulletFileLoader BulletWorldImporter BulletSoftBody BulletDynamics BulletCollision BulletInverseDynamicsUtils BulletInverseDynamics LinearMath OpenGLWindow gwen BussIK Bullet3Common ${PYTHON_LIBRARIES})

View File

@@ -33,12 +33,37 @@ project ("pybullet")
}
end
if not _OPTIONS["no-enet"] then
includedirs {"../../examples/ThirdPartyLibs/enet/include"}
if os.is("Windows") then
defines { "WIN32" }
links {"Ws2_32","Winmm"}
end
if os.is("Linux") then
end
if os.is("MacOSX") then
end
links {"enet"}
files {
"../../examples/SharedMemory/PhysicsClientUDP.cpp",
"../../examples/SharedMemory/PhysicsClientUDP.h",
"../../examples/SharedMemory/PhysicsClientUDP_C_API.cpp",
"../../examples/SharedMemory/PhysicsClientUDP_C_API.h",
}
defines {"BT_ENABLE_ENET"}
end
files {
"pybullet.c",
"../../examples/SharedMemory/IKTrajectoryHelper.cpp",
"../../examples/SharedMemory/IKTrajectoryHelper.h",
"../../examples/ExampleBrowser/InProcessExampleBrowser.cpp",
"../../examples/SharedMemory/TinyRendererVisualShapeConverter.cpp",
"../../examples/SharedMemory/TinyRendererVisualShapeConverter.cpp",
"../../examples/SharedMemory/TinyRendererVisualShapeConverter.h",
"../../examples/OpenGLWindow/SimpleCamera.cpp",
"../../examples/OpenGLWindow/SimpleCamera.h",
@@ -64,6 +89,8 @@ project ("pybullet")
"../../examples/SharedMemory/PhysicsServerCommandProcessor.h",
"../../examples/SharedMemory/PhysicsClientSharedMemory.cpp",
"../../examples/SharedMemory/PhysicsClientSharedMemory.h",
"../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp",
"../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.h",
"../../examples/SharedMemory/PhysicsClientC_API.cpp",
"../../examples/SharedMemory/PhysicsClientC_API.h",
"../../examples/SharedMemory/Win32SharedMemory.cpp",

View File

@@ -1,7 +1,9 @@
#include "../SharedMemory/PhysicsClientC_API.h"
#include "../SharedMemory/PhysicsDirectC_API.h"
#include "../SharedMemory/SharedMemoryInProcessPhysicsC_API.h"
#ifdef BT_ENABLE_ENET
#include "../SharedMemory/PhysicsClientUDP_C_API.h"
#endif //BT_ENABLE_ENET
#ifdef __APPLE__
#include <Python/Python.h>
@@ -22,6 +24,7 @@ enum eCONNECT_METHOD {
eCONNECT_GUI = 1,
eCONNECT_DIRECT = 2,
eCONNECT_SHARED_MEMORY = 3,
eCONNECT_UDP = 4,
};
static PyObject* SpamError;
@@ -60,8 +63,8 @@ static PyObject* pybullet_connectPhysicsServer(PyObject* self, PyObject* args) {
int method = eCONNECT_GUI;
if (!PyArg_ParseTuple(args, "i", &method)) {
PyErr_SetString(SpamError,
"connectPhysicsServer expected argument eCONNECT_GUI, "
"eCONNECT_DIRECT or eCONNECT_SHARED_MEMORY");
"connectPhysicsServer expected argument GUI, "
"DIRECT, SHARED_MEMORY or UDP");
return NULL;
}
@@ -85,6 +88,18 @@ static PyObject* pybullet_connectPhysicsServer(PyObject* self, PyObject* args) {
sm = b3ConnectSharedMemory(SHARED_MEMORY_KEY);
break;
}
case eCONNECT_UDP:
{
#ifdef BT_ENABLE_ENET
sm = b3ConnectPhysicsUDP("localhost", 1234);
#else
PyErr_SetString(SpamError, "UDP is not enabled in this pybullet build");
return NULL;
#endif //BT_ENABLE_ENET
break;
}
default: {
PyErr_SetString(SpamError, "connectPhysicsServer unexpected argument");
@@ -2401,6 +2416,8 @@ initpybullet(void)
eCONNECT_SHARED_MEMORY); // user read
PyModule_AddIntConstant(m, "DIRECT", eCONNECT_DIRECT); // user read
PyModule_AddIntConstant(m, "GUI", eCONNECT_GUI); // user read
PyModule_AddIntConstant(m, "UDP", eCONNECT_UDP); // user read
PyModule_AddIntConstant(m, "TORQUE_CONTROL", CONTROL_MODE_TORQUE);
PyModule_AddIntConstant(m, "VELOCITY_CONTROL",

View File

@@ -41,7 +41,10 @@ ENDIF()
../../examples/SharedMemory/PhysicsServerCommandProcessor.h
../../examples/SharedMemory/PhysicsClientSharedMemory.cpp
../../examples/SharedMemory/PhysicsClientSharedMemory.h
../../examples/SharedMemory/PhysicsClientC_API.cpp
../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp
../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.h
../../examples/SharedMemory/PhysicsClientC_API.cpp
../../examples/SharedMemory/PhysicsClientC_API.h
../../examples/SharedMemory/PhysicsLoopBack.cpp
../../examples/SharedMemory/PhysicsLoopBack.h

View File

@@ -17,6 +17,8 @@ project ("Test_SharedMemoryPhysicsClient")
"../../examples/SharedMemory/PhysicsClient.h",
"../../examples/SharedMemory/PhysicsClientSharedMemory.cpp",
"../../examples/SharedMemory/PhysicsClientSharedMemory.h",
"../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp",
"../../examples/SharedMemory/PhysicsClientSharedMemory_C_API.h",
"../../examples/SharedMemory/PhysicsClientC_API.cpp",
"../../examples/SharedMemory/PhysicsClientC_API.h",
"../../examples/SharedMemory/Win32SharedMemory.cpp",

View File

@@ -3,6 +3,10 @@
#include "SharedMemory/PhysicsClientC_API.h"
#endif //PHYSICS_SHARED_MEMORY
#ifdef PHYSICS_UDP
#include "SharedMemory/PhysicsClientUDP_C_API.h"
#endif//PHYSICS_UDP
#ifdef PHYSICS_LOOP_BACK
#include "SharedMemory/PhysicsLoopBackC_API.h"
#endif //PHYSICS_LOOP_BACK
@@ -224,7 +228,7 @@ void testSharedMemory(b3PhysicsClientHandle sm)
#endif
}
///perform some simulation steps for testing
for ( i=0;i<100;i++)
for ( i=0;i<10000;i++)
{
b3SharedMemoryStatusHandle statusHandle;
int statusType;
@@ -319,11 +323,17 @@ int main(int argc, char* argv[])
b3PhysicsClientHandle sm = b3CreateInProcessPhysicsServerAndConnect(argc,argv);
#endif //__APPLE__
#endif
#ifdef PHYSICS_SHARED_MEMORY
b3PhysicsClientHandle sm = b3ConnectSharedMemory(SHARED_MEMORY_KEY);
#endif //PHYSICS_SHARED_MEMORY
#ifdef PHYSICS_UDP
b3PhysicsClientHandle sm = b3ConnectPhysicsUDP("localhost",1234);
#endif //PHYSICS_UDP
testSharedMemory(sm);
}
#endif

View File

@@ -0,0 +1,165 @@
/* client.cpp */
#include <stdio.h>
#include <string.h>
#include <enet/enet.h>
int main(int argc, char* argv[]) {
ENetHost *client;
ENetAddress address;
ENetPeer *peer;
ENetEvent event;
char message[1024];
int serviceResult;
puts("Starting client");
if (enet_initialize() != 0) {
fprintf(stderr, "Error initialising enet");
exit(EXIT_FAILURE);
}
client = enet_host_create(NULL, /* create a client host */
1, /* number of clients */
2, /* number of channels */
57600 / 8, /* incoming bandwith */
14400 / 8); /* outgoing bandwith */
if (client == NULL) {
fprintf(stderr, "Could not create client host");
exit(EXIT_FAILURE);
}
enet_address_set_host(&address, "localhost");
address.port = 1234;
peer = enet_host_connect(client,
&address, /* address to connect to */
2, /* number of channels */
0); /* user data supplied to
the receiving host */
if (peer == NULL) {
fprintf(stderr, "No available peers for initiating an ENet "
"connection.\n");
exit(EXIT_FAILURE);
}
/* Try to connect to server within 5 seconds */
if (enet_host_service(client, &event, 5000) > 0 &&
event.type == ENET_EVENT_TYPE_CONNECT)
{
puts("Connection to server succeeded.");
}
else
{
/* Either the 5 seconds are up or a disconnect event was */
/* received. Reset the peer in the event the 5 seconds */
/* had run out without any significant event. */
enet_peer_reset(peer);
fprintf(stderr, "Connection to server failed.");
exit(EXIT_FAILURE);
}
while (true)
{
serviceResult = 1;
/* Keep doing host_service until no events are left */
while (serviceResult > 0)
{
serviceResult = enet_host_service(client, &event, 0);
if (serviceResult > 0)
{
switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT:
printf("A new client connected from %x:%u.\n",
event.peer->address.host,
event.peer->address.port);
event.peer->data = (void*)"New User";
break;
case ENET_EVENT_TYPE_RECEIVE:
printf("A packet of length %u containing '%s' was "
"received from %s on channel %u.\n",
event.packet->dataLength,
event.packet->data,
event.peer->data,
event.channelID);
/* Clean up the packet now that we're done using it.
> */
enet_packet_destroy(event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
printf("%s disconected.\n", event.peer->data);
break;
}
}
else if (serviceResult > 0)
{
puts("Error with servicing the client");
exit(EXIT_FAILURE);
}
}
printf("Say> ");
gets_s(message, 1024);
if (strcmp(message, "exit") == 0 ||
strcmp(message, "quit") == 0) {
break;
}
if (strlen(message) > 0) {
ENetPacket *packet = enet_packet_create(message, strlen
(message) + 1, ENET_PACKET_FLAG_RELIABLE);
enet_peer_send(peer, 0, packet);
}
}
enet_peer_disconnect(peer, 0);
/* Allow up to 3 seconds for the disconnect to succeed */
/* and drop any packets received packets */
while (enet_host_service(client, &event, 3000) > 0)
{
switch (event.type)
{
case ENET_EVENT_TYPE_RECEIVE:
enet_packet_destroy(event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
puts("Disconnection succeeded.");
break;
}
}
enet_host_destroy(client);
enet_deinitialize();
return 0;
}

View File

@@ -1,12 +1,12 @@
project ("Test_enet_client")
project ("Test_enet_chat_client")
language "C++"
kind "ConsoleApp"
includedirs {"../../../examples/ThirdPartyLibs/enet/include"}
includedirs {"../../../../examples/ThirdPartyLibs/enet/include"}
if os.is("Windows") then
defines { "WIN32" }

View File

@@ -0,0 +1,103 @@
/* server.cpp */
#include <stdio.h>
#include <enet/enet.h>
int main(int argc, char *argv[])
{
ENetAddress address;
ENetHost *server;
ENetEvent event;
int serviceResult;
puts("Starting server");
if (enet_initialize() != 0)
{
puts("Error initialising enet");
exit(EXIT_FAILURE);
}
/* Bind the server to the default localhost. */
/* A specific host address can be specified by */
/* enet_address_set_host (& address, "x.x.x.x"); */
address.host = ENET_HOST_ANY;
/* Bind the server to port 1234. */
address.port = 1234;
server = enet_host_create(&address,
32, /* number of clients */
2, /* number of channels */
0, /* Any incoming bandwith */
0); /* Any outgoing bandwith */
if (server == NULL)
{
puts("Could not create server host");
exit(EXIT_FAILURE);
}
while (true)
{
serviceResult = 1;
/* Keep doing host_service until no events are left */
while (serviceResult > 0)
{
/* Wait up to 1000 milliseconds for an event. */
serviceResult = enet_host_service(server, &event, 1000);
if (serviceResult > 0)
{
switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT:
printf("A new client connected from %x:%u.\n",
event.peer->address.host,
event.peer->address.port);
/* Store any relevant client information here. */
event.peer->data = (void*)"Client information";
break;
case ENET_EVENT_TYPE_RECEIVE:
printf("A packet of length %u containing '%s' was "
"received from %s on channel %u.\n",
event.packet->dataLength,
event.packet->data,
event.peer->data,
event.channelID);
/* Tell all clients about this message */
enet_host_broadcast(server, 0, event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
printf("%s disconected.\n", event.peer->data);
/* Reset the peer's client information. */
event.peer->data = NULL;
break;
}
}
else if (serviceResult > 0)
{
puts("Error with servicing the server");
exit(EXIT_FAILURE);
}
}
}
enet_host_destroy(server);
enet_deinitialize();
return 0;
}

View File

@@ -1,12 +1,12 @@
project ("Test_enet_server")
project ("Test_enet_chat_server")
language "C++"
kind "ConsoleApp"
includedirs {"../../../examples/ThirdPartyLibs/enet/include"}
includedirs {"../../../../examples/ThirdPartyLibs/enet/include"}
if os.is("Windows") then
defines { "WIN32" }

View File

@@ -0,0 +1,25 @@
project ("Test_enet_nat_punchthrough_client")
language "C++"
kind "ConsoleApp"
includedirs {"../../../../examples/ThirdPartyLibs/enet/include"}
if os.is("Windows") then
defines { "WIN32" }
links {"Ws2_32","Winmm"}
end
if os.is("Linux") then
end
if os.is("MacOSX") then
end
links {"enet"}
files {
"main.cpp",
}

View File

@@ -0,0 +1,26 @@
project ("Test_enet_nat_punchthrough_server")
language "C++"
kind "ConsoleApp"
includedirs {"../../../../examples/ThirdPartyLibs/enet/include"}
if os.is("Windows") then
defines { "WIN32" }
links {"Ws2_32","Winmm"}
end
if os.is("Linux") then
end
if os.is("MacOSX") then
end
links {"enet"}
files {
"main.cpp",
}