aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/shared/general/RenderDebug/src/ClientServer.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /APEX_1.4/shared/general/RenderDebug/src/ClientServer.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'APEX_1.4/shared/general/RenderDebug/src/ClientServer.cpp')
-rw-r--r--APEX_1.4/shared/general/RenderDebug/src/ClientServer.cpp1133
1 files changed, 1133 insertions, 0 deletions
diff --git a/APEX_1.4/shared/general/RenderDebug/src/ClientServer.cpp b/APEX_1.4/shared/general/RenderDebug/src/ClientServer.cpp
new file mode 100644
index 00000000..f48171b4
--- /dev/null
+++ b/APEX_1.4/shared/general/RenderDebug/src/ClientServer.cpp
@@ -0,0 +1,1133 @@
+#include "ClientServer.h"
+#include "GetArgs.h"
+#include "PsCommLayer.h"
+#include "PsCommStream.h"
+#include "PsArray.h"
+#include "PsUserAllocated.h"
+#include "PxIntrinsics.h"
+#include "PsMutex.h"
+#include "PsThread.h"
+#include "PsString.h"
+#include "PsTime.h"
+#include <stdio.h>
+
+#define MAX_SERVER_COMMAND_STRING 16384
+
+enum PacketType
+{
+ PT_PRIMITIVES = 100,
+ PT_COMMAND,
+ PT_ACK,
+ PT_COMM_VERSION,
+ PT_FINALIZE_FRAME,
+ PT_APPLICATION_NAME,
+ PT_REQUEST_REMOTE_RESOURCE,
+ PT_REMOTE_RESOURCE,
+ PT_INPUT_EVENT
+};
+
+struct NetworkCommmand
+{
+ NetworkCommmand(void)
+ {
+ mPacketType = PT_COMMAND;
+ mCommandLength = 0;
+ mCommand = NULL;
+ }
+ uint32_t mPacketType;
+ uint32_t mCommandLength;
+ char *mCommand;
+};
+
+struct NetworkFrame
+{
+ NetworkFrame(void)
+ {
+ mPacketType = PT_PRIMITIVES;
+ }
+
+ uint32_t getPrefixSize(void) const
+ {
+ return sizeof(NetworkFrame)-(sizeof(void *)*2);
+ }
+
+ uint32_t mPacketType;
+ uint32_t mFrameCount;
+ uint32_t mPrimType;
+ uint32_t mPrimCount;
+ uint32_t mDataLength;
+ void *mData;
+ void *mBaseData;
+};
+
+#define MAX_RESOURCE_STRING 256
+
+class RequestRemoteResource
+{
+public:
+ uint32_t mCommand;
+ char mNameSpace[MAX_RESOURCE_STRING];
+ char mResourceName[MAX_RESOURCE_STRING];
+};
+
+class RemoteResourcePacket
+{
+public:
+ uint32_t mCommand;
+ uint32_t mLength;
+ uint32_t mBigEndian;
+ char mNameSpace[MAX_RESOURCE_STRING];
+ char mResourceName[MAX_RESOURCE_STRING];
+};
+
+class RemoteResource : public RemoteResourcePacket
+{
+public:
+ RemoteResource(void)
+ {
+ mData = NULL;
+ }
+ void *mData;
+};
+
+typedef physx::shdfnd::Array< NetworkFrame > NetworkFrameArray;
+typedef physx::shdfnd::Array< NetworkCommmand > NetworkCommandArray;
+typedef physx::shdfnd::Array< RemoteResource > RemoteResourceArray;
+typedef physx::shdfnd::Array< RENDER_DEBUG::InputEvent > InputEventArray;
+
+
+static PX_INLINE void swap4Bytes(void* _data)
+{
+ char *data = static_cast<char *>(_data);
+ char one_byte;
+ one_byte = data[0]; data[0] = data[3]; data[3] = one_byte;
+ one_byte = data[1]; data[1] = data[2]; data[2] = one_byte;
+}
+
+static PX_INLINE bool isBigEndian()
+{
+ int32_t i = 1;
+ return *(reinterpret_cast<char*>(&i))==0;
+}
+
+
+struct ServerCommandString
+{
+ ServerCommandString(void)
+ {
+ mCommandString[0] = 0;
+ }
+ char mCommandString[MAX_SERVER_COMMAND_STRING];
+};
+
+class ClientServerImpl : public ClientServer, public physx::shdfnd::UserAllocated
+{
+ PX_NOCOPY(ClientServerImpl)
+public:
+ ClientServerImpl(void)
+ {
+
+ }
+
+ ClientServerImpl(RENDER_DEBUG::RenderDebug::Desc &desc) :
+ mIncomingNetworkFrames(PX_DEBUG_EXP("ClientServer::mIncomingNetworkFrames")),
+ mNetworkFrames(PX_DEBUG_EXP("ClientServer::mNetworkFrames")),
+ mNetworkCommands(PX_DEBUG_EXP("ClientServer::mNetworkCommands")),
+ mRemoteResources(PX_DEBUG_EXP("ClientServer::mRemoteResource"))
+ {
+ mSkipFrame = false;
+ physx::shdfnd::strlcpy(mApplicationName,512,desc.applicationName);
+ mStreamName[0] = 0;
+ mDataSent = false;
+ mServerStallCallback = desc.serverStallCallback;
+ mRenderDebugResource = desc.renderDebugResource;
+ mBadVersion = true; // the version number is presumed bad until we know otherwise
+ mMaxServerWait = desc.maxServerWait;
+ mReceivedAck = true;
+ mCurrentNetworkFrame = 0;
+ mLastProcessNetworkFrame = 0;
+ mCommStream = NULL;
+ mCommLayer = NULL;
+ mCurrentCommLayer = NULL;
+ mLastFrame = 0;
+ mHaveApplicationName = false;
+ mMeshId = 100000; // base mesh id
+ mUsedMeshId = false;
+ mIsServer = desc.runMode == RENDER_DEBUG::RenderDebug::RM_SERVER;
+ mStreamCount = 1;
+ mWasConnected = false;
+ mCommLayer = createCommLayer(desc.hostName,desc.portNumber,mIsServer);
+ setStreamFilename(desc.streamFileName);
+ if ( mCommLayer == NULL )
+ {
+ desc.errorCode = "Failed to create connection";
+ }
+ else if ( !mIsServer )
+ {
+ sendVersionPacket();
+ }
+
+ }
+
+ virtual ~ClientServerImpl(void)
+ {
+ if ( mCommLayer )
+ {
+ mCommLayer->release();
+ }
+ if ( mCommStream )
+ {
+ mCommStream->release();
+ }
+ releaseNetworkFrames();
+ releaseIncomingNetworkFrames();
+ releaseRemoteResources();
+ releaseNetworkCommands();
+ }
+
+ void sendVersionPacket(void)
+ {
+ if ( !mCurrentCommLayer ) return;
+ uint32_t packet[2];
+ packet[0] = PT_COMM_VERSION;
+ packet[1] = RENDER_DEBUG_COMM_VERSION;
+ mCurrentCommLayer->sendMessage(packet,sizeof(packet));
+ }
+
+ void sendApplicationNamePacket(void)
+ {
+ if ( !mCurrentCommLayer ) return;
+ uint32_t packet[(512/4)+1];
+ packet[0] = PT_APPLICATION_NAME;
+ physx::intrinsics::memCopy(&packet[1],mApplicationName,512);
+ mCurrentCommLayer->sendMessage(packet,sizeof(packet));
+ }
+
+ virtual void release(void)
+ {
+ delete this;
+ }
+
+ virtual bool isServer(void) const
+ {
+ return mIsServer;
+ }
+
+ virtual void recordPrimitives(uint32_t frameCount,
+ uint32_t primType,
+ uint32_t primCount,
+ uint32_t dataLength,
+ const void *data)
+ {
+ mLastFrame = frameCount;
+
+ if ( mCurrentCommLayer && !mIsServer )
+ {
+ if ( mCurrentCommLayer->isConnected() ) // if we still have a connection..
+ {
+ // If we haven't caught up in
+ uint32_t sendSize = sizeof(uint32_t)*5+dataLength;
+ void *sendData = PX_ALLOC(sendSize,"sendData");
+ uint32_t *sendDataHeader = static_cast<uint32_t *>(sendData);
+ sendDataHeader[0] = PT_PRIMITIVES;
+ sendDataHeader[1] = frameCount;
+ sendDataHeader[2] = primType;
+ sendDataHeader[3] = primCount;
+ sendDataHeader[4] = dataLength;
+ sendDataHeader+=5;
+ physx::intrinsics::memCopy(sendDataHeader,data,dataLength);
+ mCurrentCommLayer->sendMessage(sendData,sendSize);
+ PX_FREE(sendData);
+ mDataSent = true;
+ }
+ }
+
+ }
+
+ void processNetworkData(void)
+ {
+ bool isBigEndianPacket;
+ uint32_t newDataSize = mCurrentCommLayer->peekMessage(isBigEndianPacket);
+ bool endOfFrame = false;
+ while ( newDataSize && !endOfFrame )
+ {
+ void *readData = PX_ALLOC(newDataSize,"readData");
+ bool freeReadData = true;
+ uint32_t rlen = mCurrentCommLayer->getMessage(readData,newDataSize,isBigEndianPacket);
+
+ if ( rlen == newDataSize )
+ {
+ bool needEndianSwap = false;
+ uint32_t type = *static_cast<uint32_t *>(readData);
+ if ( isBigEndianPacket != isBigEndian() )
+ {
+ needEndianSwap = true;
+ }
+ if ( needEndianSwap )
+ {
+ swap4Bytes(&type);
+ }
+ switch ( type )
+ {
+ case PT_APPLICATION_NAME:
+ {
+ uint32_t *packet = static_cast<uint32_t *>(readData);
+ physx::intrinsics::memCopy(mApplicationName,packet+1,512);
+ mHaveApplicationName = true;
+ }
+ break;
+ case PT_COMM_VERSION:
+ {
+ if ( mIsServer ) // if we are the server, tell the client our version number
+ {
+ sendVersionPacket(); // inform the client that we are of the same version
+ }
+ else
+ {
+ sendApplicationNamePacket(); // if we are the client, tell the server the name of our application
+ }
+ uint32_t *packet = static_cast<uint32_t *>(readData);
+ if ( needEndianSwap )
+ {
+ swap4Bytes(&packet[1]);
+ }
+ if ( packet[1] == RENDER_DEBUG_COMM_VERSION ) // if it is the same version as us, no problems!
+ {
+ mBadVersion = false;
+ }
+ else
+ {
+ mBadVersion = true;
+ }
+ }
+ break;
+ case PT_PRIMITIVES:
+ if ( !mBadVersion ) // if we have agreed upon each other's version number then we can process the data stream, otherwise..not so much
+ {
+ // as expected..
+ NetworkFrame nframe;
+ uint32_t *header = static_cast<uint32_t *>(readData);
+
+ nframe.mFrameCount = header[1];
+ nframe.mPrimType = header[2];
+ nframe.mPrimCount = header[3];
+ nframe.mDataLength = header[4];
+ nframe.mData = &header[5];
+
+ if ( needEndianSwap )
+ {
+ swap4Bytes(&nframe.mFrameCount);
+ swap4Bytes(&nframe.mPrimType);
+ swap4Bytes(&nframe.mPrimCount);
+ swap4Bytes(&nframe.mDataLength);
+ }
+
+ nframe.mBaseData = readData;
+ freeReadData = false;
+
+ if ( nframe.mFrameCount != mCurrentNetworkFrame )
+ {
+ for (uint32_t j=0; j<mIncomingNetworkFrames.size(); j++)
+ {
+ NetworkFrame &nf = mIncomingNetworkFrames[j];
+ uint32_t pcount = nf.mPrimCount;
+ const uint8_t *scan = static_cast<const uint8_t *>(nf.mData);
+ for (uint32_t i=0; i<pcount; i++)
+ {
+ RENDER_DEBUG::DebugPrimitive *prim = const_cast<RENDER_DEBUG::DebugPrimitive *>(reinterpret_cast<const RENDER_DEBUG::DebugPrimitive *>(scan));
+ if ( needEndianSwap )
+ {
+ endianSwap(prim);
+ }
+
+ switch ( uint32_t(prim->mCommand) )
+ {
+ case RENDER_DEBUG::DebugCommand::DEBUG_CREATE_TRIANGLE_MESH:
+ {
+ RENDER_DEBUG::DebugCreateTriangleMesh *d = static_cast< RENDER_DEBUG::DebugCreateTriangleMesh *>(prim);
+ uint32_t *hackMeshId = reinterpret_cast<uint32_t *>(d);
+ hackMeshId[2]+=mMeshId;
+ mUsedMeshId = true;
+ }
+ break;
+ case RENDER_DEBUG::DebugCommand::DEBUG_REFRESH_TRIANGLE_MESH_VERTICES:
+ {
+ RENDER_DEBUG::DebugRefreshTriangleMeshVertices *d = static_cast< RENDER_DEBUG::DebugRefreshTriangleMeshVertices *>(prim);
+ uint32_t *hackMeshId = reinterpret_cast<uint32_t *>(d);
+ hackMeshId[2]+=mMeshId;
+ mUsedMeshId = true;
+ }
+ break;
+ case RENDER_DEBUG::DebugCommand::DEBUG_RENDER_TRIANGLE_MESH_INSTANCES:
+ {
+ RENDER_DEBUG::DebugRenderTriangleMeshInstances *d = static_cast<RENDER_DEBUG::DebugRenderTriangleMeshInstances *>(prim);
+ uint32_t *hackMeshId = reinterpret_cast<uint32_t *>(d);
+ hackMeshId[2]+=mMeshId;
+ mUsedMeshId = true;
+ }
+ break;
+ case RENDER_DEBUG::DebugCommand::DEBUG_RENDER_POINTS:
+ {
+ RENDER_DEBUG::DebugRenderPoints *d = static_cast<RENDER_DEBUG::DebugRenderPoints *>(prim);
+ uint32_t *hackMeshId = reinterpret_cast<uint32_t *>(d);
+ hackMeshId[2]+=mMeshId;
+ mUsedMeshId = true;
+ }
+ break;
+ case RENDER_DEBUG::DebugCommand::DEBUG_CONVEX_HULL:
+ printf("Debug me");
+ break;
+ case RENDER_DEBUG::DebugCommand::DEBUG_RELEASE_TRIANGLE_MESH:
+ {
+ RENDER_DEBUG::DebugReleaseTriangleMesh *d = static_cast<RENDER_DEBUG::DebugReleaseTriangleMesh *>(prim);
+ d->mMeshId+=mMeshId;
+ mUsedMeshId = true;
+ }
+ break;
+ case RENDER_DEBUG::DebugCommand::DEBUG_SKIP_FRAME:
+ mSkipFrame = true;
+ break;
+ }
+ uint32_t plen = RENDER_DEBUG::DebugCommand::getPrimtiveSize(*prim);
+ scan+=plen;
+ }
+ }
+ endOfFrame = true;
+ if ( mSkipFrame )
+ {
+ mSkipFrame = false;
+ releaseIncomingNetworkFrames();
+ }
+ else
+ {
+ releaseNetworkFrames(); // release previous network frames
+ mNetworkFrames = mIncomingNetworkFrames;
+ mIncomingNetworkFrames.clear();
+ }
+ mCurrentNetworkFrame = nframe.mFrameCount;
+ mIncomingNetworkFrames.pushBack(nframe);
+
+ if ( mIsServer )
+ {
+ // if we are the server, we should send an ACK to the client so that they know that we processed their frame of data.
+ uint32_t ack = PT_ACK;
+ mCurrentCommLayer->sendMessage(&ack,sizeof(ack));
+ }
+ }
+ else
+ {
+ mIncomingNetworkFrames.pushBack(nframe);
+ }
+ }
+ break;
+ case PT_COMMAND:
+ if ( !mBadVersion )
+ {
+ NetworkCommmand c;
+ uint32_t *header = static_cast<uint32_t *>(readData);
+ c.mCommandLength = header[1];
+ if ( needEndianSwap )
+ {
+ swap4Bytes(&c.mCommandLength);
+ }
+ c.mCommand = static_cast<char*>(PX_ALLOC(c.mCommandLength+1,"NetworkCommand"));
+ physx::intrinsics::memCopy(c.mCommand,&header[2],c.mCommandLength+1);
+ mNetworkCommandMutex.lock();
+ mNetworkCommands.pushBack(c);
+ mNetworkCommandMutex.unlock();
+ }
+ break;
+ case PT_REMOTE_RESOURCE:
+ if ( !mBadVersion )
+ {
+ RemoteResourcePacket *rr = static_cast<RemoteResourcePacket *>(readData);
+ if ( needEndianSwap )
+ {
+ swap4Bytes(&rr->mLength);
+ swap4Bytes(&rr->mBigEndian);
+ }
+ uint32_t bigEndianPacket = isBigEndianPacket ? uint32_t(1) : uint32_t(0);
+ PX_UNUSED(bigEndianPacket);
+ PX_ASSERT( bigEndianPacket == rr->mBigEndian );
+ RemoteResource sr;
+ RemoteResourcePacket *prr = static_cast< RemoteResource *>(&sr);
+ *prr = *rr;
+ sr.mData = PX_ALLOC(sr.mLength,"RemoteResource");
+ rr++;
+ physx::intrinsics::memCopy(sr.mData,rr,sr.mLength);
+ mRemoteResources.pushBack(sr);
+ }
+ break;
+ case PT_INPUT_EVENT:
+ {
+ RENDER_DEBUG::InputEvent e = *static_cast<const RENDER_DEBUG::InputEvent *>(readData);
+ if ( needEndianSwap )
+ {
+ swap4Bytes(&e.mId);
+ swap4Bytes(&e.mCommunicationsFrame);
+ swap4Bytes(&e.mRenderFrame);
+ swap4Bytes(&e.mEventType);
+ swap4Bytes(&e.mSensitivity);
+ swap4Bytes(&e.mDigitalValue);
+ swap4Bytes(&e.mAnalogValue);
+ swap4Bytes(&e.mMouseX);
+ swap4Bytes(&e.mMouseY);
+ swap4Bytes(&e.mMouseDX);
+ swap4Bytes(&e.mMouseDY);
+ swap4Bytes(&e.mWindowSizeX);
+ swap4Bytes(&e.mWindowSizeY);
+ swap4Bytes(&e.mEyePosition[0]);
+ swap4Bytes(&e.mEyePosition[1]);
+ swap4Bytes(&e.mEyePosition[2]);
+ swap4Bytes(&e.mEyeDirection[0]);
+ swap4Bytes(&e.mEyeDirection[1]);
+ swap4Bytes(&e.mEyeDirection[2]);
+ }
+ mInputEvents.pushBack(e);
+ }
+ break;
+ case PT_REQUEST_REMOTE_RESOURCE:
+ if ( !mBadVersion )
+ {
+ const RequestRemoteResource *rr = static_cast<const RequestRemoteResource *>(readData);
+ if ( mRenderDebugResource )
+ {
+ uint32_t len;
+ const void *data = mRenderDebugResource->requestResource(rr->mNameSpace,rr->mResourceName,len);
+ if ( data )
+ {
+ sendRemoteResource(rr->mNameSpace,rr->mResourceName,data,len);
+ mRenderDebugResource->releaseResource(data,len,rr->mNameSpace,rr->mResourceName);
+ }
+ }
+ }
+ break;
+ case PT_FINALIZE_FRAME:
+ {
+ uint32_t *header = static_cast<uint32_t *>(readData);
+ if ( needEndianSwap )
+ {
+ swap4Bytes(&header[1]);
+ }
+ mCurrentNetworkFrame = header[1];
+ if ( mIsServer )
+ {
+ // if we are the server, we should send an ACK to the client so that they know that we processed their frame of data.
+ uint32_t ack = PT_ACK;
+ mCurrentCommLayer->sendMessage(&ack,sizeof(ack));
+ }
+ }
+ break;
+ case PT_ACK:
+ mReceivedAck = true;
+ break;
+ }
+ }
+ if ( freeReadData )
+ {
+ PX_FREE(readData);
+ }
+ newDataSize = mCurrentCommLayer->peekMessage(isBigEndianPacket);
+ }
+
+ }
+
+ void processFrame(RENDER_DEBUG::ProcessRenderDebug *processRenderDebug,RENDER_DEBUG::RenderDebugInterface *iface)
+ {
+ if ( !mCurrentCommLayer ) return;
+
+ if ( mIsServer )
+ {
+ if ( mCommStream && !mCommStream->isValid() )
+ {
+ mCommStream->release();
+ mCommStream = NULL;
+ mCurrentCommLayer = mCommLayer;
+ }
+ if ( mCurrentCommLayer->hasClient() )
+ {
+ mWasConnected = true;
+ }
+ else if ( mWasConnected )
+ {
+ if ( mCommStream )
+ {
+ internalSetStreamFilename(mStreamName);
+ }
+ mWasConnected = false;
+ }
+ }
+
+
+ if ( !mCurrentCommLayer->isConnected() ) return;
+
+ processNetworkData();
+
+ if ( !mNetworkFrames.empty() )
+ {
+ uint32_t lastDisplayType = 0;
+
+ for (uint32_t j=0; j<mNetworkFrames.size(); j++)
+ {
+ NetworkFrame &nf = mNetworkFrames[j];
+
+ if ( j == 0 )
+ {
+ lastDisplayType = nf.mPrimType;
+ }
+
+ uint32_t ipcount = nf.mPrimCount;
+ if ( ipcount > MAX_SEND_BUFFER )
+ {
+ ipcount = MAX_SEND_BUFFER;
+ }
+ const uint8_t *scan = static_cast<const uint8_t *>(nf.mData);
+ uint32_t pcount = 0;
+ for (uint32_t i=0; i<ipcount; i++)
+ {
+ RENDER_DEBUG::DebugPrimitive *prim = const_cast<RENDER_DEBUG::DebugPrimitive *>(reinterpret_cast<const RENDER_DEBUG::DebugPrimitive *>(scan));
+ bool includePrimitive = true;
+ if ( mCurrentNetworkFrame == mLastProcessNetworkFrame )
+ {
+ switch ( uint32_t(prim->mCommand) )
+ {
+ case RENDER_DEBUG::DebugCommand::DEBUG_MESSAGE:
+ case RENDER_DEBUG::DebugCommand::DEBUG_CREATE_TRIANGLE_MESH:
+ case RENDER_DEBUG::DebugCommand::DEBUG_REFRESH_TRIANGLE_MESH_VERTICES:
+ case RENDER_DEBUG::DebugCommand::DEBUG_RELEASE_TRIANGLE_MESH:
+ case RENDER_DEBUG::DebugCommand::DEBUG_CREATE_CUSTOM_TEXTURE:
+ case RENDER_DEBUG::DebugCommand::DEBUG_REGISTER_INPUT_EVENT:
+ case RENDER_DEBUG::DebugCommand::DEBUG_RESET_INPUT_EVENTS:
+ case RENDER_DEBUG::DebugCommand::DEBUG_UNREGISTER_INPUT_EVENT:
+ case RENDER_DEBUG::DebugCommand::DEBUG_SKIP_FRAME:
+ includePrimitive = false;
+ break;
+ }
+ }
+ if ( includePrimitive )
+ {
+ mDebugPrimitives[pcount] = prim;
+ pcount++;
+ }
+ uint32_t plen = RENDER_DEBUG::DebugCommand::getPrimtiveSize(*prim);
+ scan+=plen;
+ }
+ if ( lastDisplayType != nf.mPrimType )
+ {
+ processRenderDebug->flush(iface,static_cast<RENDER_DEBUG::ProcessRenderDebug::DisplayType>(lastDisplayType));
+ lastDisplayType = nf.mPrimType;
+ }
+ processRenderDebug->processRenderDebug(const_cast<const RENDER_DEBUG::DebugPrimitive **>(reinterpret_cast<RENDER_DEBUG::DebugPrimitive **>(mDebugPrimitives)),
+ pcount,
+ iface,
+ static_cast<RENDER_DEBUG::ProcessRenderDebug::DisplayType>(nf.mPrimType));
+ }
+ processRenderDebug->flush(iface,static_cast<RENDER_DEBUG::ProcessRenderDebug::DisplayType>(lastDisplayType));
+ processRenderDebug->flushFrame(iface);
+ mLastProcessNetworkFrame = mCurrentNetworkFrame;
+ }
+ }
+
+ void releaseNetworkCommands(void)
+ {
+ for (uint32_t i=0; i<mNetworkCommands.size(); i++)
+ {
+ NetworkCommmand nc = mNetworkCommands[i];
+ PX_FREE(nc.mCommand);
+ }
+ mNetworkCommands.clear();
+ }
+
+ void releaseNetworkFrames(void)
+ {
+ for (uint32_t i=0; i<mNetworkFrames.size(); i++)
+ {
+ NetworkFrame &nf = mNetworkFrames[i];
+ PX_FREE(nf.mBaseData);
+ }
+ mNetworkFrames.clear();
+ }
+
+ void releaseIncomingNetworkFrames(void)
+ {
+ for (uint32_t i=0; i<mIncomingNetworkFrames.size(); i++)
+ {
+ NetworkFrame &nf = mIncomingNetworkFrames[i];
+ PX_FREE(nf.mBaseData);
+ }
+ mIncomingNetworkFrames.clear();
+ }
+
+
+ virtual bool serverWait(void)
+ {
+ bool ret = false;
+
+ // Here we wait up until the maximum wait count to receive an ack from the server.
+ if ( !mIsServer && mCurrentCommLayer && mCurrentCommLayer->isConnected() )
+ {
+ if ( mReceivedAck )
+ {
+ mReceivedAck = false;
+ }
+ else
+ {
+ bool ok = false;
+ for (uint32_t i=0; i<mMaxServerWait; i++)
+ {
+ if ( !isConnected() )
+ {
+ ok = false;
+ break;
+ }
+ processNetworkData();
+ if ( mReceivedAck )
+ {
+ mReceivedAck = false;
+ ok = true;
+ break;
+ }
+ else
+ {
+ mTime.getElapsedSeconds();
+ physx::shdfnd::Time::Second diff = mTime.peekElapsedSeconds();
+ while ( diff < 0.001 )
+ {
+ diff = mTime.peekElapsedSeconds();
+ processNetworkData();
+ if ( mReceivedAck )
+ {
+ mReceivedAck = false;
+ ok = true;
+ break;
+ }
+ physx::shdfnd::Thread::sleep(0); // we are low priority since we are in a wait loop, give up timeslice to other thread if necessary
+ }
+ if ( ok )
+ {
+ break;
+ }
+ if ( mServerStallCallback )
+ {
+ if ( !mServerStallCallback->continueWaitingForServer(i+1) )
+ {
+ ok = false;
+ break;
+ }
+ }
+ }
+ }
+ if ( !ok )
+ {
+ mCurrentCommLayer = NULL;
+ if ( mCommLayer )
+ {
+ mCommLayer->release();
+ mCommLayer = NULL;
+ }
+ if ( mCommStream )
+ {
+ mCommStream->release();
+ mCommStream = NULL;
+ }
+
+ releaseNetworkFrames();
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ virtual const char **getCommand(uint32_t &argc)
+ {
+ const char **ret = NULL;
+ argc = 0;
+
+ mNetworkCommandMutex.lock();
+
+ if ( !mNetworkCommands.empty() )
+ {
+ NetworkCommmand nc = mNetworkCommands[0];
+ mNetworkCommands.remove(0);
+ physx::intrinsics::memCopy(mCurrentCommand,nc.mCommand,nc.mCommandLength+1);
+ PX_FREE(nc.mCommand);
+ ret = mParser.getArgs(mCurrentCommand,argc);
+ }
+
+ mNetworkCommandMutex.unlock();
+
+ return ret;
+ }
+
+ virtual bool sendCommand(const char *cmd)
+ {
+ bool ret = false;
+
+ if ( cmd && mCurrentCommLayer)
+ {
+ uint32_t slen = uint32_t(strlen(cmd));
+ if ( slen < MAX_SERVER_COMMAND_STRING )
+ {
+ uint32_t sendSize = sizeof(uint32_t)*2+slen+1;
+ uint32_t *sendData = static_cast<uint32_t *>(PX_ALLOC(sendSize,"SendCommand"));
+ sendData[0] = PT_COMMAND;
+ sendData[1] = slen;
+ physx::intrinsics::memCopy(&sendData[2],cmd,slen+1);
+ mCurrentCommLayer->sendMessage(sendData,sendSize);
+ PX_FREE(sendData);
+ ret = true;
+ }
+ }
+
+ return ret;
+ }
+
+ virtual bool isConnected(void)
+ {
+ if ( !mCurrentCommLayer ) return false;
+ if ( mIsServer )
+ {
+ bool hasClient = mCurrentCommLayer->hasClient();
+ if ( !hasClient && mUsedMeshId )
+ {
+ mUsedMeshId = false;
+ mMeshId+=10000; // increment the baseline mesh-id for the next time the client runs.
+ mHaveApplicationName = false;
+ }
+ return hasClient;
+ }
+ return mCurrentCommLayer->isConnected();
+ }
+
+ virtual uint32_t getCommunicationsFrame(void) const
+ {
+ if ( mIsServer )
+ {
+ return mCurrentNetworkFrame;
+ }
+ return mLastFrame;
+ }
+
+ virtual void finalizeFrame(uint32_t frameCount)
+ {
+ if ( mDataSent )
+ {
+ mDataSent = false;
+ return;
+ }
+ if ( !mCurrentCommLayer )
+ {
+ return;
+ }
+ if ( mIsServer )
+ {
+ return;
+ }
+
+ if ( !mCurrentCommLayer->isConnected() )
+ {
+ return;
+ }
+ uint32_t packet[2];
+ packet[0] = PT_FINALIZE_FRAME;
+ packet[1] = frameCount;
+ mCurrentCommLayer->sendMessage(packet,sizeof(packet));
+ }
+
+ virtual const char * getRemoteApplicationName(void)
+ {
+ const char *ret = NULL;
+
+ if ( mIsServer && mHaveApplicationName )
+ {
+ ret = mApplicationName;
+ }
+
+ return ret;
+ }
+
+ /**
+ \brief Transmits an arbitrary block of binary data to the remote machine. The block of data can have a command and id associated with it.
+
+ It is important to note that due to the fact the RenderDebug system is synchronized every single frame, it is strongly recommended
+ that you only use this feature for relatively small data items; probably on the order of a few megabytes at most. If you try to do
+ a very large transfer, in theory it would work, but it might take a very long time to complete and look like a hang since it will
+ essentially be blocking.
+
+ \param nameSpace The namespace associated with this data transfer, for example this could indicate a remote file request.
+ \param resourceName The name of the resource associated with this data transfer, for example the id could be the file name of a file transfer request.
+ \param data The block of binary data to transmit, you are responsible for maintaining endian correctness of the internal data if necessary.
+ \param dlen The length of the lock of data to transmit.
+
+ \return Returns true if the data was queued to be transmitted, false if it failed.
+ */
+ virtual bool sendRemoteResource(const char *nameSpace,
+ const char *resourceName,
+ const void *data,
+ uint32_t dlen)
+ {
+ bool ret = false;
+
+ if ( mCurrentCommLayer && mCurrentCommLayer->isConnected() && data && dlen )
+ {
+ uint32_t sendLen = sizeof(RemoteResourcePacket)+dlen;
+ RemoteResourcePacket *sendPacket = static_cast<RemoteResourcePacket*>(PX_ALLOC(sendLen,"RemoteResource"));
+ RemoteResourcePacket &rr = *sendPacket;
+
+ rr.mCommand = PT_REMOTE_RESOURCE;
+ rr.mLength = dlen;
+ rr.mBigEndian = isBigEndian() ? uint32_t( 1) : uint32_t( 0);
+ physx::shdfnd::strlcpy(rr.mNameSpace,MAX_RESOURCE_STRING,nameSpace);
+ physx::shdfnd::strlcpy(rr.mResourceName,MAX_RESOURCE_STRING,resourceName);
+ RemoteResourcePacket *dest = sendPacket;
+ dest++;
+ physx::intrinsics::memCopy(dest,data,dlen);
+ ret = mCurrentCommLayer->sendMessage(sendPacket,sendLen);
+ PX_FREE(sendPacket);
+
+ }
+
+
+ return ret;
+ }
+
+ /**
+ \brief This function allows you to request a file from the remote machine by name. If successful it will be returned via 'getRemoteData'
+
+ \param nameSpace The namespace field associated with this request which will be returned by 'getRemoteData'
+ \param resourceName The resource name being requested from the remote machine.
+
+ \return Returns true if the request was queued to be transmitted, false if it failed.
+ */
+ virtual bool requestRemoteResource(const char *nameSpace,
+ const char *resourceName)
+ {
+ bool ret = false;
+
+ if ( mCurrentCommLayer && mCurrentCommLayer->isConnected() )
+ {
+ RequestRemoteResource rr;
+ rr.mCommand = PT_REQUEST_REMOTE_RESOURCE;
+ physx::shdfnd::strlcpy(rr.mNameSpace,MAX_RESOURCE_STRING,nameSpace);
+ physx::shdfnd::strlcpy(rr.mResourceName,MAX_RESOURCE_STRING,resourceName);
+ ret = mCurrentCommLayer->sendMessage(&rr,sizeof(rr));
+ }
+
+ return ret;
+ }
+
+ /**
+ \brief Retrieves a block of remotely transmitted binary data.
+
+ \param nameSpace A a reference to a pointer which will store the namespace associated with this data transfer, for example this could indicate a remote file request.
+ \param resourceName A reference to a pointer which will store the resource name associated with this data transfer, for example the id could be the file name of a file transfer request.
+ \param dlen A reference that will contain length of the lock of data received.
+ \param remoteIsBigEndian A reference to a boolean which will be set to true if the remote machine that sent this data is big endian format.
+
+ \retrun A pointer to the block of data received.
+ */
+ virtual const void * getRemoteResource(const char *&nameSpace,
+ const char *&resourceName,
+ uint32_t &dlen,
+ bool &remoteIsBigEndian)
+ {
+ const void *ret = NULL;
+
+ nameSpace = NULL;
+ resourceName = NULL;
+ dlen = 0;
+ remoteIsBigEndian = 0;
+ if ( !mRemoteResources.empty() )
+ {
+ if ( mCurrentRemoteResource.mData )
+ {
+ PX_FREE(mCurrentRemoteResource.mData);
+ mCurrentRemoteResource.mData = NULL;
+ }
+ mCurrentRemoteResource = mRemoteResources[0];
+ mRemoteResources.remove(0);
+
+ ret = mCurrentRemoteResource.mData;
+ nameSpace = mCurrentRemoteResource.mNameSpace;
+ resourceName = mCurrentRemoteResource.mResourceName;
+ dlen = mCurrentRemoteResource.mLength;
+ remoteIsBigEndian = mCurrentRemoteResource.mBigEndian ? true : false;
+
+ }
+
+ return ret;
+ }
+
+ void releaseRemoteResources(void)
+ {
+ if ( mCurrentRemoteResource.mData )
+ {
+ PX_FREE(mCurrentRemoteResource.mData);
+ mCurrentRemoteResource.mData = NULL;
+ }
+ for (uint32_t i=0; i<mRemoteResources.size(); i++)
+ {
+ RemoteResource &rr = mRemoteResources[i];
+ PX_FREE(rr.mData);
+ }
+ mRemoteResources.clear();
+ }
+
+ virtual void sendInputEvent(const RENDER_DEBUG::InputEvent &ev)
+ {
+ if ( mCurrentCommLayer )
+ {
+ RENDER_DEBUG::InputEvent e = ev;
+ e.mReserved = PT_INPUT_EVENT;
+ mCurrentCommLayer->sendMessage(&e,sizeof(RENDER_DEBUG::InputEvent));
+ }
+ }
+
+ virtual const RENDER_DEBUG::InputEvent *getInputEvent(bool flush)
+ {
+ const RENDER_DEBUG::InputEvent *ret = NULL;
+
+ if ( !mInputEvents.empty() )
+ {
+ mCurrentInputEvent = mInputEvents[0];
+ ret = &mCurrentInputEvent;
+ if ( flush )
+ {
+ mInputEvents.remove(0);
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ \brief Set the base file name to record communications stream; or NULL to disable it.
+
+ \param fileName The base name of the file to record the communications channel stream to, or NULL to disable it.
+ */
+ virtual bool setStreamFilename(const char *fileName)
+ {
+ if ( fileName )
+ {
+ physx::shdfnd::strlcpy(mStreamName,256,fileName);
+ }
+ else
+ {
+ mStreamName[0] = 0;
+ if ( mCommStream )
+ {
+ mCommStream->release();
+ mCommStream = NULL;
+ }
+ }
+ return internalSetStreamFilename(mStreamName);
+ }
+
+ bool internalSetStreamFilename(const char *fileName)
+ {
+ bool ret = true;
+
+ mCurrentCommLayer = mCommLayer;
+
+ if ( mIsServer && fileName[0] )
+ {
+ if ( mCommStream )
+ {
+ mCommStream->release();
+ mCommStream = NULL;
+ }
+ if ( fileName )
+ {
+ char scratch[512];
+ sprintf(scratch,"%s%02d.nvcs", fileName, mStreamCount );
+ mCommStream = createCommStream(scratch,true,mCommLayer);
+ if ( mCommStream )
+ {
+ mStreamCount++;
+ mCurrentCommLayer = static_cast< CommLayer *>(mCommStream);
+ }
+ else
+ {
+ ret = false;
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ \brief Begin playing back a communications stream recording
+
+ \param fileName The name of the previously captured communications stream file
+ */
+ virtual bool setStreamPlayback(const char *fileName)
+ {
+ if ( !mIsServer ) return false;
+ if ( mCommLayer->hasClient() ) return false;
+ if ( mCommStream )
+ {
+ mCommStream->release();
+ mCommStream = NULL;
+ }
+ bool ret = false;
+ mCurrentCommLayer = mCommLayer;
+ mCommStream = createCommStream(fileName,false,mCommLayer);
+ if ( mCommStream )
+ {
+ ret = true;
+ mCurrentCommLayer = mCommStream;
+ }
+ return ret;
+ }
+
+ bool mSkipFrame;
+ char mStreamName[256];
+ uint32_t mStreamCount;
+ bool mWasConnected;
+ bool mDataSent; // whether or not any data was sent this frame
+ bool mBadVersion;
+ bool mReceivedAck;
+ uint32_t mMeshId;
+ bool mUsedMeshId;
+ uint32_t mLastFrame;
+ bool mIsServer;
+ RENDER_DEBUG::DebugPrimitive *mDebugPrimitives[MAX_SEND_BUFFER];
+ char mCurrentCommand[MAX_SERVER_COMMAND_STRING];
+ CommLayer *mCommLayer;
+ CommStream *mCommStream;
+ CommLayer *mCurrentCommLayer;
+ uint32_t mLastProcessNetworkFrame;
+ uint32_t mCurrentNetworkFrame;
+ NetworkFrameArray mIncomingNetworkFrames;
+ NetworkFrameArray mNetworkFrames;
+ NetworkCommandArray mNetworkCommands;
+ physx::shdfnd::Mutex mNetworkCommandMutex;
+ uint32_t mMaxServerWait;
+ RENDER_DEBUG::RenderDebug::ServerStallCallback *mServerStallCallback;
+ bool mHaveApplicationName;
+ char mApplicationName[512];
+ GetArgs mParser;
+ RENDER_DEBUG::RenderDebugResource *mRenderDebugResource;
+ RemoteResource mCurrentRemoteResource;
+ RemoteResourceArray mRemoteResources;
+ RENDER_DEBUG::InputEvent mCurrentInputEvent;
+ InputEventArray mInputEvents;
+ physx::shdfnd::Time mTime;
+};
+
+ClientServer *createClientServer(RENDER_DEBUG::RenderDebug::Desc &desc)
+{
+ ClientServer *ret = NULL;
+ desc.errorCode = NULL;
+ ClientServerImpl *c = PX_NEW(ClientServerImpl)(desc);
+ if ( desc.errorCode )
+ {
+ c->release();
+ }
+ else
+ {
+ ret = static_cast< ClientServer *>(c);
+ }
+ return ret;
+}