From 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 Mon Sep 17 00:00:00 2001 From: git perforce import user Date: Tue, 25 Oct 2016 12:29:14 -0600 Subject: Initial commit: PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167] --- .../RenderDebug/src/InternalRenderDebug.cpp | 2708 ++++++++++++++++++++ 1 file changed, 2708 insertions(+) create mode 100644 APEX_1.4/shared/general/RenderDebug/src/InternalRenderDebug.cpp (limited to 'APEX_1.4/shared/general/RenderDebug/src/InternalRenderDebug.cpp') diff --git a/APEX_1.4/shared/general/RenderDebug/src/InternalRenderDebug.cpp b/APEX_1.4/shared/general/RenderDebug/src/InternalRenderDebug.cpp new file mode 100644 index 00000000..afe73340 --- /dev/null +++ b/APEX_1.4/shared/general/RenderDebug/src/InternalRenderDebug.cpp @@ -0,0 +1,2708 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2013 NVIDIA Corporation. All rights reserved. + +#include "PsHashMap.h" +#include "InternalRenderDebug.h" +#include "RenderDebug.h" +#include "RenderDebugImpl.h" +#include "ProcessRenderDebug.h" +#include "PsMemoryBuffer.h" + +#include "PsPool.h" +#include "PsString.h" +#include "PxBounds3.h" +#include "StreamIO.h" + +namespace RENDER_DEBUG +{ + +#define RENDER_STATE_STACK_SIZE 16 // maximum size of the render state stack +const float FM_PI = 3.1415926535897932384626433832795028841971693993751f; +const float FM_DEG_TO_RAD = ((2.0f * FM_PI) / 360.0f); +//const float FM_RAD_TO_DEG = (360.0f / (2.0f * FM_PI)); + + +class PostRenderDebug +{ + PX_NOCOPY(PostRenderDebug) +public: + + PostRenderDebug(void) + { + mSendBufferCount = 0; + // since all of these commands are processed internally, in memory buffers, we don't need to be endian specific. + mWorldSpace.setEndianMode(physx::PxFileBuf::ENDIAN_NONE); + mScreenSpace.setEndianMode(physx::PxFileBuf::ENDIAN_NONE); + mNoZ.setEndianMode(physx::PxFileBuf::ENDIAN_NONE); + } + + ~PostRenderDebug(void) + { + } + + PX_INLINE void postRenderDebug(DebugPrimitive *p,const RenderState &rs) + { +// if ( p->mCommand == DebugCommand::DEBUG_GRAPH ) +// return; + + uint32_t plen = DebugCommand::getPrimtiveSize(*p); + float dtime = rs.getDisplayTime(); + + switch ( p->mCommand ) + { + case DebugCommand::DEBUG_GRAPH: + { + DebugGraphStream *dgs = static_cast< DebugGraphStream *>(p); + plen = dgs->mSize; + p = reinterpret_cast(dgs->mBuffer); + dgs = static_cast< DebugGraphStream *>(p); + dgs->mSize = plen; + } + break; + case DebugCommand::DEBUG_CREATE_TRIANGLE_MESH: + { + DebugCreateTriangleMesh *dgs = static_cast< DebugCreateTriangleMesh *>(p); + plen = dgs->mSize; + p = reinterpret_cast(dgs->mBuffer); + dgs = static_cast< DebugCreateTriangleMesh *>(p); + dgs->mSize = plen; + } + break; + case DebugCommand::DEBUG_RENDER_TRIANGLE_MESH_INSTANCES: + { + DebugRenderTriangleMeshInstances *dgs = static_cast< DebugRenderTriangleMeshInstances *>(p); + plen = dgs->mSize; + p = reinterpret_cast(dgs->mBuffer); + dgs = static_cast< DebugRenderTriangleMeshInstances *>(p); + dgs->mSize = plen; + } + break; + case DebugCommand::DEBUG_CONVEX_HULL: + { + DebugConvexHull *dgs = static_cast< DebugConvexHull *>(p); + plen = dgs->mSize; + p = reinterpret_cast(dgs->mBuffer); + dgs = static_cast< DebugConvexHull *>(p); + dgs->mSize = plen; + } + + break; + case DebugCommand::DEBUG_RENDER_POINTS: + { + DebugRenderPoints *dgs = static_cast< DebugRenderPoints *>(p); + plen = dgs->mSize; + p = reinterpret_cast(dgs->mBuffer); + dgs = static_cast< DebugRenderPoints *>(p); + dgs->mSize = plen; + } + break; + case DebugCommand::DEBUG_RENDER_LINES: + { + DebugRenderLines *dgs = static_cast< DebugRenderLines *>(p); + plen = dgs->mSize; + p = reinterpret_cast(dgs->mBuffer); + dgs = static_cast< DebugRenderLines *>(p); + dgs->mSize = plen; + } + break; + case DebugCommand::DEBUG_RENDER_TRIANGLES: + { + DebugRenderTriangles *dgs = static_cast< DebugRenderTriangles *>(p); + plen = dgs->mSize; + p = reinterpret_cast(dgs->mBuffer); + dgs = static_cast< DebugRenderTriangles *>(p); + dgs->mSize = plen; + } + break; + case DebugCommand::DEBUG_REFRESH_TRIANGLE_MESH_VERTICES: + { + DebugRefreshTriangleMeshVertices *dgs = static_cast< DebugRefreshTriangleMeshVertices *>(p); + plen = dgs->mSize; + p = reinterpret_cast(dgs->mBuffer); + dgs = static_cast< DebugRefreshTriangleMeshVertices *>(p); + dgs->mSize = plen; + } + break; + } + + + if ( rs.isScreen() || p->mCommand == DebugCommand::DEBUG_GRAPH ) + { + processState(rs,mScreenSpaceRenderState,mScreenSpace,dtime); + mScreenSpace.write(&dtime,sizeof(dtime)); + mScreenSpace.write(p,plen); + } + else if ( rs.isUseZ() ) + { + processState(rs,mWorldSpaceRenderState,mWorldSpace,dtime); + mWorldSpace.write(&dtime,sizeof(dtime)); + mWorldSpace.write(p,plen); + } + else + { + processState(rs,mNoZRenderState,mNoZ,dtime); + mNoZ.write(&dtime,sizeof(dtime)); + mNoZ.write(p,plen); + } + } + + void release(void) + { + delete this; + } + + + bool processRenderDebug(ProcessRenderDebug *rd,float dtime,RENDER_DEBUG::RenderDebugInterface *iface) + { + + PX_ASSERT(dtime>=0); + process(mWorldSpace,rd,dtime,iface,ProcessRenderDebug::WORLD_SPACE); + process(mNoZ,rd,dtime,iface,ProcessRenderDebug::WORLD_SPACE_NOZ); + process(mScreenSpace,rd,dtime,iface,ProcessRenderDebug::SCREEN_SPACE); + rd->flushFrame(iface); + + new ( &mWorldSpaceRenderState ) RenderState; + new ( &mScreenSpaceRenderState ) RenderState; + new ( &mNoZRenderState ) RenderState; + + return true; + } + + PX_INLINE bool intersects(const uint8_t *a1,const uint8_t *a2,const uint8_t *b1,const uint8_t *b2) + { + bool ret = true; + if ( a1 >= b2 || b1 >= a2 ) ret = false; + return ret; + } + + // This method processes the current stream of draw commands. + // Each draw command is preceded by its 'lifetime'. + // If the object is still alive after it is processed, it is retained in the buffer. + void process(physx::PsMemoryBuffer &stream, + ProcessRenderDebug *rd, + float dtime, + RENDER_DEBUG::RenderDebugInterface *iface, + ProcessRenderDebug::DisplayType type) + { + if ( stream.tellWrite() == 0 ) return; + + uint8_t *dest = const_cast(stream.getWriteBuffer()); + + const uint8_t *sendStart = NULL; + const uint8_t *sendEnd = NULL; + + float displayTime; + uint32_t r = stream.read(&displayTime,sizeof(displayTime)); + + BlockInfo *info = NULL; + + while ( r == sizeof(displayTime) ) + { + displayTime-=dtime; + bool alive = displayTime > 0.0f; + uint32_t cmd; + r = stream.peek(&cmd,sizeof(cmd)); + + PX_ASSERT( r == sizeof(cmd) ); + PX_ASSERT( cmd < DebugCommand::DEBUG_LAST ); + + switch ( cmd ) + { + case DebugCommand::DEBUG_MESSAGE: + case DebugCommand::DEBUG_CREATE_TRIANGLE_MESH: + case DebugCommand::DEBUG_RELEASE_TRIANGLE_MESH: + case DebugCommand::DEBUG_REFRESH_TRIANGLE_MESH_VERTICES: + case DebugCommand::DEBUG_CREATE_CUSTOM_TEXTURE: + case DebugCommand::DEBUG_REGISTER_INPUT_EVENT: + case DebugCommand::DEBUG_UNREGISTER_INPUT_EVENT: + case DebugCommand::DEBUG_RESET_INPUT_EVENTS: + case DebugCommand::DEBUG_SKIP_FRAME: + alive = false; + break; + } + + const uint8_t *readLoc = stream.getReadLoc(); + DebugPrimitive *dp = const_cast(reinterpret_cast(readLoc)); + uint32_t plen = DebugCommand::getPrimtiveSize(*dp); + stream.advanceReadLoc(plen); + + if ( sendStart == NULL ) + { + sendStart = readLoc; + } + sendEnd = readLoc+plen; + + if ( dp->mCommand == DebugCommand::DEBUG_BLOCK_INFO ) + { + DebugBlockInfo *db = static_cast< DebugBlockInfo *>(dp); + info = db->mInfo; + + if ( info && info->mChanged ) + { + db->mCurrentTransform = info->mPose; + info->mChanged = false; + } + if ( info && info->mVisibleState ) + { + DebugPrimitive *setCurrentTransform = static_cast< DebugPrimitive *>(&db->mCurrentTransform); + mSendBuffer[mSendBufferCount] = setCurrentTransform; + mSendBufferCount++; + } + } + else if ( info ) + { + if ( info->mVisibleState ) + { + mSendBuffer[mSendBufferCount] = dp; + mSendBufferCount++; + } + else if (isRenderState(dp)) + { + mSendBuffer[mSendBufferCount] = dp; + mSendBufferCount++; + } + } + else + { + mSendBuffer[mSendBufferCount] = dp; + mSendBufferCount++; + } + + if ( mSendBufferCount == MAX_SEND_BUFFER ) + { + rd->processRenderDebug(mSendBuffer,mSendBufferCount,iface,type); + mSendBufferCount = 0; + sendStart = sendEnd = NULL; + } + + if ( alive ) + { + if ( sendStart && intersects(sendStart,sendEnd,dest,dest+plen+sizeof(float)) ) + { + if ( mSendBufferCount ) + { + rd->processRenderDebug(mSendBuffer,mSendBufferCount,iface,type); + } + mSendBufferCount = 0; + sendStart = sendEnd = NULL; + } + + // Store the new display time! + float *fdest = reinterpret_cast(dest); + *fdest = displayTime; + dest+=sizeof(float); + + if ( dest != reinterpret_cast(dp) ) // if the source and dest are the same, we don't need to move memory + { + memcpy(dest,dp,plen); + } + dest+=plen; + } + + r = stream.read(&displayTime,sizeof(displayTime)); + } + + if ( mSendBufferCount ) + { + rd->processRenderDebug(mSendBuffer,mSendBufferCount,iface,type); + mSendBufferCount = 0; + } + + if ( info ) + { + info->mChanged = false; + } + + stream.setWriteLoc(dest); + rd->flush(iface,type); + stream.seekRead(0); + } + + void reset(BlockInfo *info) + { + reset(mWorldSpace,info); + reset(mNoZ,info); + reset(mScreenSpace,info); + } + + // if resetInfo is NULL, then totally erase the persistent data stream. + // if resetInfo is non-NULL, then erease all parts of the stream which are associated with this data block. + void reset(physx::PsMemoryBuffer &stream,BlockInfo *resetInfo) + { + if ( stream.tellWrite() == 0 ) return; + // remove all data + if ( resetInfo ) + { + uint8_t *dest = const_cast(stream.getWriteBuffer()); + float displayTime; + uint32_t r = stream.read(&displayTime,sizeof(displayTime)); + BlockInfo *info = NULL; + while ( r == sizeof(displayTime) ) + { + char scratch[sizeof(DebugGraphStream)]; + DebugGraphStream *dgs = reinterpret_cast(scratch); + r = stream.peek(dgs,sizeof(DebugGraphStream)); + PX_ASSERT( r >= 8); + PX_ASSERT( dgs->mCommand < DebugCommand::DEBUG_LAST ); + uint32_t plen = DebugCommand::getPrimtiveSize(*dgs); + const uint8_t *readLoc = stream.getReadLoc(); + DebugPrimitive *dp = reinterpret_cast(const_cast(readLoc)); + stream.advanceReadLoc(plen); + if ( dp->mCommand == DebugCommand::DEBUG_BLOCK_INFO ) + { + DebugBlockInfo *db = static_cast< DebugBlockInfo *>(dp); + info = db->mInfo; + } + if ( info != resetInfo ) + { + // Store the new display time! + float *fdest = reinterpret_cast(dest); + *fdest = displayTime; + dest+=sizeof(float); + if ( dest != reinterpret_cast(dp) ) // if the source and dest are the same, we don't need to move memory + { + memcpy(dest,dp,plen); + } + dest+=plen; + + } + r = stream.read(&displayTime,sizeof(displayTime)); + } + stream.setWriteLoc(dest); + stream.seekRead(0); + } + else + { + // kill all saved data! + uint8_t *dest = const_cast(stream.getWriteBuffer()); + stream.setWriteLoc(dest); + stream.seekRead(0); + } + } + + void updateBufferChangeCount(const RenderState &rs) + { + if ( rs.isScreen() /*|| p->mCommand == DebugCommand::DEBUG_GRAPH*/ ) + mScreenSpaceRenderState.mChangeCount = rs.getChangeCount(); + else if ( rs.isUseZ() ) + mWorldSpaceRenderState.mChangeCount = rs.getChangeCount(); + else + mNoZRenderState.mChangeCount = rs.getChangeCount(); + } + + void updatePostDrawGroupPose (const RenderState &rs) + { + float dtime = rs.getDisplayTime(); + + if ( rs.isScreen() /*|| p->mCommand == DebugCommand::DEBUG_GRAPH*/ ) + setCurrentTransform(rs, mScreenSpaceRenderState, mScreenSpace, dtime); + else if ( rs.isUseZ() ) + setCurrentTransform(rs, mWorldSpaceRenderState, mWorldSpace, dtime); + else + setCurrentTransform(rs, mNoZRenderState, mNoZ, dtime); + } + +private: + + PX_INLINE void processState(const RenderState &source, + RenderState &dest, + physx::PsMemoryBuffer &stream, + float lifeTime) + { + if ( dest.getChangeCount() == 0 ) + { + setColor(source,dest,stream,lifeTime); + setArrowColor(source,dest,stream,lifeTime); + setTexture(source,dest,stream,lifeTime); + setArrowSize(source,dest,stream,lifeTime); + setRenderScale(source,dest,stream,lifeTime); + setUserId(source,dest,stream,lifeTime); + setStates(source,dest,stream,lifeTime); + setTextScale(source,dest,stream,lifeTime); + setCurrentTransform(source,dest,stream,lifeTime); + setBlockInfo(source,dest,stream,lifeTime); + dest.incrementChangeCount(); + } + else if ( source.getChangeCount() != dest.getChangeCount() ) + { + applyStateChanges(source,dest,stream,lifeTime); + } + } + + PX_INLINE void setColor(const RenderState &source,RenderState &dest,physx::PsMemoryBuffer &stream,float lifeTime) + { + DebugPrimitiveU32 d(DebugCommand::SET_CURRENT_COLOR,source.mColor); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mColor = source.mColor; + } + + PX_INLINE void setRenderScale(const RenderState &source,RenderState &dest,physx::PsMemoryBuffer &stream,float lifeTime) + { + DebugPrimitiveF32 d(DebugCommand::SET_CURRENT_RENDER_SCALE,source.mRenderScale); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mRenderScale = source.mRenderScale; + } + + PX_INLINE void setArrowSize(const RenderState &source,RenderState &dest,physx::PsMemoryBuffer &stream,float lifeTime) + { + DebugPrimitiveF32 d(DebugCommand::SET_CURRENT_ARROW_SIZE,source.mArrowSize); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mArrowSize = source.mArrowSize; + } + + PX_INLINE void setUserId(const RenderState &source,RenderState &dest,physx::PsMemoryBuffer &stream,float lifeTime) + { + DebugPrimitiveU32 d(DebugCommand::SET_CURRENT_USER_ID,uint32_t(source.mUserId)); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mUserId = source.mUserId; + } + + PX_INLINE void setArrowColor(const RenderState &source,RenderState &dest,physx::PsMemoryBuffer &stream,float lifeTime) + { + DebugPrimitiveU32 d(DebugCommand::SET_CURRENT_ARROW_COLOR,source.mArrowColor); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mArrowColor = source.mArrowColor; + } + + PX_INLINE void setTexture(const RenderState &source,RenderState &dest,physx::PsMemoryBuffer &stream,float lifeTime) + { + if ( dest.mTexture1 != source.mTexture1 ) + { + DebugPrimitiveU32 d(DebugCommand::SET_CURRENT_TEXTURE1,source.mTexture1); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mTexture1 = source.mTexture1; + } + if ( dest.mTexture2 != source.mTexture2 ) + { + DebugPrimitiveU32 d(DebugCommand::SET_CURRENT_TEXTURE2,source.mTexture2); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mTexture2 = source.mTexture2; + } + if ( dest.mTileRate1 != source.mTileRate2 ) + { + DebugPrimitiveF32 d(DebugCommand::SET_CURRENT_TILE1,source.mTileRate1); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mTileRate1 = source.mTileRate1; + } + if ( dest.mTileRate2 != source.mTileRate2 ) + { + DebugPrimitiveF32 d(DebugCommand::SET_CURRENT_TILE2,source.mTileRate2); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mTileRate2 = source.mTileRate2; + } + + } + + + PX_INLINE void setStates(const RenderState &source,RenderState &dest,physx::PsMemoryBuffer &stream,float lifeTime) + { + DebugPrimitiveU32 d(DebugCommand::SET_CURRENT_RENDER_STATE,source.mStates); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mStates = source.mStates; + } + + PX_INLINE void setTextScale(const RenderState &source,RenderState &dest,physx::PsMemoryBuffer &stream,float lifeTime) + { + DebugPrimitiveF32 d(DebugCommand::SET_CURRENT_TEXT_SCALE,source.mTextScale); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mTextScale = source.mTextScale; + } + + PX_INLINE void setCurrentTransform(const RenderState &source, + RenderState &dest, + physx::PsMemoryBuffer &stream,float lifeTime) + { + DebugSetCurrentTransform d(source.mPose ? *source.mPose : physx::PxMat44(physx::PxIdentity) ); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + if ( source.mPose ) + { + dest.mCurrentPose = *source.mPose; + dest.mPose = &dest.mCurrentPose; + } + else + { + dest.mPose = NULL; + } + } + + PX_INLINE void setBlockInfo(const RenderState &source,RenderState &dest,physx::PsMemoryBuffer &stream,float lifeTime) + { + DebugBlockInfo d(source.mBlockInfo); + stream.write(&lifeTime,sizeof(lifeTime)); + stream.write(&d,sizeof(d)); + dest.mBlockInfo = source.mBlockInfo; + } + + + void applyStateChanges(const RenderState &source,RenderState &dest,physx::PsMemoryBuffer &stream,float lifeTime) + { + if ( source.mColor != dest.mColor ) + { + setColor(source,dest,stream,lifeTime); + } + if ( source.mArrowColor != dest.mArrowColor ) + { + setArrowColor(source,dest,stream,lifeTime); + } + { + setTexture(source,dest,stream,lifeTime); + } + if ( source.mRenderScale != dest.mRenderScale ) + { + setRenderScale(source,dest,stream,lifeTime); + } + if ( source.mArrowSize != dest.mArrowSize ) + { + setArrowSize(source,dest,stream,lifeTime); + } + if ( source.mUserId != dest.mUserId ) + { + setUserId(source,dest,stream,lifeTime); + } + if ( source.mStates != dest.mStates ) + { + setStates(source,dest,stream,lifeTime); + } + if ( source.mTextScale != dest.mTextScale ) + { + setTextScale(source,dest,stream,lifeTime); + } + if ( source.mPose != dest.mPose ) + { + if ( !sameMat44(source.mPose,dest.mPose) ) + { + setCurrentTransform(source,dest,stream,lifeTime); + } + } + if ( source.mBlockInfo != dest.mBlockInfo ) + { + setBlockInfo(source,dest,stream,lifeTime); + } + dest.mChangeCount = source.mChangeCount; + } + + bool sameMat44(const physx::PxMat44 *a,const physx::PxMat44 *b) const + { + if ( a == b ) return true; + if ( a == NULL || b == NULL ) return false; + const float *f1 = a->front(); + const float *f2 = b->front(); + for (uint32_t i=0; i<16; i++) + { + float diff = physx::PxAbs(f1[i]-f2[i]); + if ( diff > 0.000001f ) return false; + } + return true; + } + + bool isRenderState(const DebugPrimitive * const dp) const + { + return( dp->mCommand == DebugCommand::SET_CURRENT_COLOR || + dp->mCommand == DebugCommand::SET_CURRENT_TILE1 || + dp->mCommand == DebugCommand::SET_CURRENT_TILE2 || + dp->mCommand == DebugCommand::SET_CURRENT_TEXTURE1 || + dp->mCommand == DebugCommand::SET_CURRENT_TEXTURE2 || + dp->mCommand == DebugCommand::SET_CURRENT_ARROW_COLOR || + dp->mCommand == DebugCommand::SET_CURRENT_ARROW_SIZE || + dp->mCommand == DebugCommand::SET_CURRENT_RENDER_SCALE || + dp->mCommand == DebugCommand::SET_CURRENT_USER_ID || + dp->mCommand == DebugCommand::SET_CURRENT_RENDER_STATE || + dp->mCommand == DebugCommand::SET_CURRENT_TEXT_SCALE || + dp->mCommand == DebugCommand::SET_CURRENT_TRANSFORM ); + } + + physx::PsMemoryBuffer mWorldSpace; + physx::PsMemoryBuffer mScreenSpace; + physx::PsMemoryBuffer mNoZ; + + RenderState mWorldSpaceRenderState; + RenderState mScreenSpaceRenderState; + RenderState mNoZRenderState; + + uint32_t mSendBufferCount; + const DebugPrimitive *mSendBuffer[MAX_SEND_BUFFER]; +}; + + + + +class InternalRenderDebug : public RenderDebugImpl, public physx::shdfnd::UserAllocated, PostRenderDebug +{ +public: + + InternalRenderDebug(ProcessRenderDebug *process,RenderDebugHook *renderDebugHook) + { + mCanSkip = true; + mRenderDebugHook = renderDebugHook; + mFrameTime = 1.0f / 60.0f; + mBlockIndex = 0; + mStackIndex = 0; + mUpdateCount = 0; + mOwnProcess = false; + if ( process ) + { + mProcessRenderDebug = process; + } + else + { + mProcessRenderDebug = createProcessRenderDebug(); + mOwnProcess = true; + } + initColors(); + } + + ~InternalRenderDebug(void) + { + if ( mOwnProcess ) + { + mProcessRenderDebug->release(); + } + } + + virtual uint32_t getUpdateCount(void) const + { + return mUpdateCount; + } + + virtual bool renderImpl(float dtime,RENDER_DEBUG::RenderDebugInterface *iface) + { + bool ret = false; + + ret = PostRenderDebug::processRenderDebug(mProcessRenderDebug,dtime,iface); + mUpdateCount++; + + mProcessRenderDebug->finalizeFrame(); + mCanSkip = true; // next frame state + + return ret; + } + + virtual void reset(int32_t blockIndex=-1) // -1 reset *everything*, 0 = reset everything except stuff inside blocks, > 0 reset a specific block of data. + { + if ( blockIndex == -1 ) + { + PostRenderDebug::reset(NULL); + } + else + { + const physx::shdfnd::HashMap::Entry *e = mBlocksHash.find(uint32_t(blockIndex)); + if ( e ) + { + BlockInfo *b = e->second; + PostRenderDebug::reset(b); + } + } + } + + + virtual void drawGrid(bool zup=false,uint32_t gridSize=40) // draw a grid. + { + DrawGrid d(zup,gridSize); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + } + + virtual void pushRenderState(void) + { + PX_ASSERT( mStackIndex < RENDER_STATE_STACK_SIZE ); + if ( mStackIndex < RENDER_STATE_STACK_SIZE ) + { + mRenderStateStack[mStackIndex] = mCurrentState; + if ( mCurrentState.mPose ) + { + mRenderStateStack[mStackIndex].mPose = &mRenderStateStack[mStackIndex].mCurrentPose; + } + mStackIndex++; + } + } + + virtual void popRenderState(void) + { + PX_ASSERT(mStackIndex); + if ( mStackIndex > 0 ) + { + mStackIndex--; + mCurrentState = mRenderStateStack[mStackIndex]; + if ( mRenderStateStack[mStackIndex].mPose ) + { + mCurrentState.mPose = &mCurrentState.mCurrentPose; + } + PostRenderDebug::updateBufferChangeCount(mCurrentState); + mCurrentState.incrementChangeCount(); + } + } + + + virtual void setCurrentColor(uint32_t color=0xFFFFFF,uint32_t arrowColor=0xFF0000) + { + mCurrentState.mColor = color; + mCurrentState.mArrowColor = arrowColor; + mCurrentState.incrementChangeCount(); + } + + virtual uint32_t getCurrentColor(void) const + { + return mCurrentState.mColor; + } + + /** + \brief Set the current debug texture + + \param textureEnum1 Which predefined texture to use as the primary texture + \param tileRate1 The tiling rate to use for the primary texture + \param textureEnum2 Which (optional) predefined texture to use as the primary texture + \param tileRate2 The tiling rate to use for the secondary texture + */ + virtual void setCurrentTexture(DebugTextures::Enum textureEnum1,float tileRate1,DebugTextures::Enum textureEnum2,float tileRate2) + { + mCurrentState.mTexture1 = textureEnum1; + mCurrentState.mTexture2 = textureEnum2; + mCurrentState.mTileRate1 = tileRate1; + mCurrentState.mTileRate2 = tileRate2; + mCurrentState.incrementChangeCount(); + } + + /** + \brief Gets the current tiling rate of the primary texture + + \return The current tiling rate of the primary texture + */ + virtual float getCurrentTile1(void) const + { + return mCurrentState.mTileRate1; + } + + /** + \brief Gets the current tiling rate of the secondary texture + + \return The current tiling rate of the secondary texture + */ + virtual float getCurrentTile2(void) const + { + return mCurrentState.mTileRate2; + } + + /** + \brief Gets the current debug texture + + \return The current texture id + */ + virtual DebugTextures::Enum getCurrentTexture1(void) const + { + return static_cast(mCurrentState.mTexture1); + } + + /** + \brief Gets the current debug texture + + \return The current texture id + */ + virtual DebugTextures::Enum getCurrentTexture2(void) const + { + return static_cast(mCurrentState.mTexture2); + } + + + virtual uint32_t getCurrentArrowColor(void) const + { + return mCurrentState.mArrowColor; + } + + + virtual void setCurrentUserId(int32_t userId) + { + mCurrentState.mUserId = userId; + mCurrentState.incrementChangeCount(); + } + + virtual int32_t getCurrentUserId(void) + { + return mCurrentState.mUserId; + } + + virtual void setCurrentDisplayTime(float displayTime=0.0001f) + { + mCurrentState.mDisplayTime = displayTime; + mCurrentState.incrementChangeCount(); + } + + virtual float getRenderScale(void) + { + return mCurrentState.mRenderScale; + } + + virtual void setRenderScale(float scale) + { + mCurrentState.mRenderScale = scale; + mCurrentState.incrementChangeCount(); + } + + virtual void setCurrentState(uint32_t states=0) + { + mCurrentState.mStates = states; + mCurrentState.incrementChangeCount(); + } + + virtual void addToCurrentState(RENDER_DEBUG::DebugRenderState::Enum state) // OR this state flag into the current state. + { + mCurrentState.mStates|=state; + mCurrentState.incrementChangeCount(); + } + + virtual void removeFromCurrentState(RENDER_DEBUG::DebugRenderState::Enum state) // Remove this bit flat from the current state + { + mCurrentState.mStates&=~state; + mCurrentState.incrementChangeCount(); + } + + virtual void setCurrentTextScale(float textScale) + { + mCurrentState.mTextScale = textScale; + mCurrentState.incrementChangeCount(); + } + + virtual void setCurrentArrowSize(float arrowSize) + { + mCurrentState.mArrowSize = arrowSize; + mCurrentState.incrementChangeCount(); + } + + virtual uint32_t getCurrentState(void) const + { + return mCurrentState.mStates; + } + + virtual void setRenderState(uint32_t states=0, // combination of render state flags + uint32_t color=0xFFFFFF, // base color + float displayTime=0.0001f, // duration of display items. + uint32_t arrowColor=0xFF0000, // secondary color, usually used for arrow head + float arrowSize=0.1f, + float renderScale=1.0f, + float textScale=1.0f) // seconary size, usually used for arrow head size. + { + uint32_t saveChangeCount = mCurrentState.mChangeCount; + new ( &mCurrentState ) RenderState(states,color,displayTime,arrowColor,arrowSize,renderScale,textScale); + mCurrentState.mChangeCount = saveChangeCount; + mCurrentState.incrementChangeCount(); + } + + + virtual uint32_t getRenderState(uint32_t &color,float &displayTime,uint32_t &arrowColor,float &arrowSize,float &renderScale,float & /*textScale*/) const + { + color = mCurrentState.mColor; + displayTime = mCurrentState.mDisplayTime; + arrowColor = mCurrentState.mArrowColor; + arrowSize = mCurrentState.mArrowSize; + renderScale = mCurrentState.mRenderScale; + return mCurrentState.mStates; + } + + + virtual void endDrawGroup(void) + { + popRenderState(); + PostRenderDebug::updatePostDrawGroupPose(mCurrentState); + } + + virtual void setDrawGroupVisible(int32_t blockId,bool state) + { + const physx::shdfnd::HashMap::Entry *e = mBlocksHash.find(uint32_t(blockId)); + if ( e ) + { + BlockInfo *b = e->second; + if ( b->mVisibleState != state ) + { + b->mVisibleState = state; + } + } + } + + virtual void debugPolygon(uint32_t pcount,const physx::PxVec3 *points) + { + if ( mCurrentState.isSolid() ) + { + PX_ASSERT( pcount >= 3 ); + PX_ASSERT( pcount <= 256 ); + bool wasOverlay = mCurrentState.hasRenderState(RENDER_DEBUG::DebugRenderState::SolidWireShaded); + if( wasOverlay ) + { + mCurrentState.clearRenderState(RENDER_DEBUG::DebugRenderState::SolidWireShaded); + mCurrentState.incrementChangeCount(); + } + const physx::PxVec3 *v1 = &points[0]; + const physx::PxVec3 *v2 = &points[1]; + const physx::PxVec3 *v3 = &points[2]; + debugTri(*v1, *v2, *v3); + for (uint32_t i=3; i 4 ) + { + subdivision = 4; + } + physx::PxMat44 pose = physx::PxMat44(physx::PxIdentity); + pose.setPosition(pos); + debugOrientedSphere(radius, subdivision, pose); + } + + void debugOrientedSphere(float radius, uint32_t subdivision,const physx::PxMat44 &transform) + { + pushRenderState(); + if ( mCurrentState.mPose ) + { + physx::PxMat44 xform = *mCurrentState.mPose*transform; + setPose(xform); + } + else + { + setPose(transform); + } + + DebugSphere d(radius, subdivision); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + + popRenderState(); + } + + // a squashed sphere + virtual void debugOrientedSphere(const physx::PxVec3 &radius, uint32_t subdivision,const physx::PxMat44 &transform) + { + pushRenderState(); + if ( mCurrentState.mPose ) + { + physx::PxMat44 xform = *mCurrentState.mPose*transform; + setPose(xform); + } + else + { + setPose(transform); + } + + DebugSquashedSphere d(radius, subdivision); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + + popRenderState(); + } + + + virtual void debugCapsule(float radius,float height,uint32_t subdivision) + { + DebugCapsule d(radius,height,subdivision); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + } + + virtual void debugCapsuleTapered(float radius1, float radius2, float height, uint32_t subdivision) + { + DebugTaperedCapsule d(radius1, radius2, height, subdivision); + PostRenderDebug::postRenderDebug(&d, mCurrentState); + } + + virtual void debugCylinder(float radius,float height,bool closeSides,uint32_t subdivision) + { + DebugCylinder d(radius,height,subdivision,closeSides); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + } + + virtual void debugCircle(const physx::PxVec3 ¢er,float radius,uint32_t subdivision) + { + pushRenderState(); + physx::PxMat44 transform(physx::PxIdentity); + transform.setPosition(center); + if ( mCurrentState.mPose ) + { + physx::PxMat44 xform = *mCurrentState.mPose*transform; + setPose(xform); + } + else + { + setPose(transform); + } + DebugCircle d(radius,subdivision,false); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + popRenderState(); + } + + virtual void debugAxes(const physx::PxMat44 &transform,float distance=0.1f,float brightness=1.0f,bool showXYZ=false,bool showRotation=false, uint32_t axisSwitch=4, DebugAxesRenderMode::Enum renderMode = DebugAxesRenderMode::DEBUG_AXES_RENDER_SOLID) + { + DebugAxes d(transform,distance,brightness,showXYZ,showRotation,axisSwitch, renderMode); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + } + + virtual void debugArc(const physx::PxVec3 ¢er,const physx::PxVec3 &p1,const physx::PxVec3 &p2,float arrowSize=0.1f,bool showRoot=false) + { + DebugArc d(center,p1,p2,arrowSize,showRoot); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + } + + virtual void debugThickArc(const physx::PxVec3 ¢er,const physx::PxVec3 &p1,const physx::PxVec3 &p2,float thickness=0.02f,bool showRoot=false) + { + DebugThickArc d(center,p1,p2,thickness,showRoot); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + } + + virtual void debugDetailedSphere(const physx::PxVec3 &pos,float radius,uint32_t stepCount) + { + DebugDetailedSphere d(pos,radius,stepCount); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + } + + /** + \brief Debug visualize a text string rendered using a simple 2d font. + + \param x The X position of the text in normalized screen space 0 is the left of the screen and 1 is the right of the screen. + \param y The Y position of the text in normalized screen space 0 is the top of the screen and 1 is the bottom of the screen. + \param scale The scale of the font; these are not true-type fonts, so this is simple sprite scales. A scale of 0.5 is a nice default value. + \param shadowOffset The font is displayed with a drop shadow to make it easier to distinguish against the background; a value between 1 to 6 looks ok. + \param forceFixWidthNumbers This bool controls whether numeric values are printed as fixed width or not. + \param textColor the 32 bit ARGB value color to use for this piece of text. + \param fmt A printf style format string followed by optional arguments + */ + virtual void debugText2D(float x, + float y, + float scale, + float shadowOffset, + bool forceFixWidthNumbers, + uint32_t textColor, + const char *fmt,...) + { + char wbuff[16384]; + wbuff[16383] = 0; + va_list arg; + va_start( arg, fmt ); + physx::shdfnd::vsnprintf(wbuff,sizeof(wbuff)-1, fmt, arg); + va_end(arg); + DebugText2D dt(physx::PxVec2(x,y),scale,shadowOffset,forceFixWidthNumbers,textColor,wbuff); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + + virtual void debugText(const physx::PxVec3 &pos,const char *fmt,...) + { + char wbuff[16384]; + wbuff[16383] = 0; + va_list arg; + va_start( arg, fmt ); + physx::shdfnd::vsnprintf(wbuff,sizeof(wbuff)-1, fmt, arg); + va_end(arg); + physx::PxMat44 pose = mCurrentState.mPose ? *mCurrentState.mPose : physx::PxMat44(physx::PxIdentity); + DebugText dt(pos,pose,wbuff); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + virtual void setViewMatrix(const physx::PxMat44 &view) + { + memcpy( mViewMatrix44, &view, 16*sizeof( float ) ); + updateVP(); + if ( mProcessRenderDebug ) + { + const physx::PxMat44 *view44 = (reinterpret_cast(mViewMatrix44)); + mProcessRenderDebug->setViewMatrix(*view44); + } + } + + virtual void setProjectionMatrix(const physx::PxMat44 &projection) + { + memcpy( mProjectionMatrix44, &projection, 16*sizeof( float ) ); + updateVP(); + } + + void updateVP(void) + { + float* e = mViewProjectionMatrix44; + for( int c = 0; c < 4; ++c ) + { + for( int r = 0; r < 4; ++r, ++e ) + { + float sum = 0; + for( int k = 0; k < 4; ++k ) + { + sum += mProjectionMatrix44[r+(k<<2)]*mViewMatrix44[k+(c<<2)]; + } + *e = sum; + } + } + // grab the world-space eye position. + const physx::PxMat44 *view44 = (reinterpret_cast(mViewMatrix44)); + physx::PxMat44 viewInverse = view44->inverseRT(); + mEyePos = viewInverse.transform( physx::PxVec3( 0.0f, 0.0f, 0.0f )); + } + + virtual const float* getViewProjectionMatrix(void) const + { + return mViewProjectionMatrix44; + } + + virtual const physx::PxMat44* getViewProjectionMatrixTyped(void) const + { + return (reinterpret_cast(mViewProjectionMatrix44)); + } + + + virtual const float *getViewMatrix(void) const + { + return mViewMatrix44; // returns column major array + } + + virtual const physx::PxMat44 *getViewMatrixTyped(void) const + { + return (reinterpret_cast(mViewMatrix44)); // returns column major array + } + + + virtual const float *getProjectionMatrix(void) const + { + return mProjectionMatrix44; // returns column major array + } + + virtual const physx::PxMat44 *getProjectionMatrixTyped(void) const + { + return (reinterpret_cast(mProjectionMatrix44)); // returns column major array + } + + + // quat to rotate v0 t0 v1 + PX_INLINE physx::PxQuat rotationArc(const physx::PxVec3& v0, const physx::PxVec3& v1) + { + const physx::PxVec3 cross = v0.cross(v1); + const float d = v0.dot(v1); + if(d<=-0.99999f) + return (physx::PxAbs(v0.x)<0.1f ? physx::PxQuat(0.0f, v0.z, -v0.y, 0.0f) : physx::PxQuat(v0.y, -v0.x, 0.0, 0.0)).getNormalized(); + + const float s = physx::PxSqrt((1+d)*2), r = 1/s; + + return physx::PxQuat(cross.x*r, cross.y*r, cross.z*r, s*0.5f).getNormalized(); + } + + + /** + \brief A convenience method to convert a position and direction vector into a 4x4 transform + + \param p0 Start position + \param p1 Rotate to position + \param xform Output transform + + */ + virtual void rotationArc(const physx::PxVec3 &p0,const physx::PxVec3 &p1,physx::PxMat44 &xform) + { + physx::PxVec3 dir = p1-p0; + dir.normalize(); + + physx::PxTransform t; + t.p = p0; + t.q = rotationArc(physx::PxVec3(0,1.0f,0),dir); + xform = physx::PxMat44(t); + } + + /** + \brief A convenience method to convert a position and direction vector into a 4x4 transform + + \param p0 The origin + \param p1 Rotate to position + \param xform Ouput transform + + */ + virtual void rotationArc(const float p0[3],const float p1[3],float xform[16]) + { + rotationArc(*(reinterpret_cast(p0)),*(reinterpret_cast(p1)),*(reinterpret_cast(xform))); + } + + virtual void eulerToQuat(const physx::PxVec3 &angles, physx::PxQuat &q) // angles are in degrees. + { + float roll = angles.x*0.5f*FM_DEG_TO_RAD; + float pitch = angles.y*0.5f*FM_DEG_TO_RAD; + float yaw = angles.z*0.5f*FM_DEG_TO_RAD; + + float cr = cosf(roll); + float cp = cosf(pitch); + float cy = cosf(yaw); + + float sr = sinf(roll); + float sp = sinf(pitch); + float sy = sinf(yaw); + + float cpcy = cp * cy; + float spsy = sp * sy; + float spcy = sp * cy; + float cpsy = cp * sy; + + float x = ( sr * cpcy - cr * spsy); + float y = ( cr * spcy + sr * cpsy); + float z = ( cr * cpsy - sr * spcy); + float w = cr * cpcy + sr * spsy; + q = physx::PxQuat(x,y,z,w); + } + + virtual int32_t beginDrawGroup(const physx::PxMat44 &pose) + { + pushRenderState(); + + setRenderState(RENDER_DEBUG::DebugRenderState::InfiniteLifeSpan,0xFFFFFF,0.0001f,0xFF0000,0.1f,mCurrentState.mRenderScale,mCurrentState.mTextScale); + + mBlockIndex++; + mCurrentState.mBlockInfo = mBlocks.construct(); + mCurrentState.mBlockInfo->mHashValue = mBlockIndex; + mCurrentState.mBlockInfo->mPose = pose; + mBlocksHash[mBlockIndex] = mCurrentState.mBlockInfo; + + return int32_t(mBlockIndex); + } + + virtual void setDrawGroupPose(int32_t blockId,const physx::PxMat44 &pose) + { + const physx::shdfnd::HashMap::Entry *e = mBlocksHash.find(uint32_t(blockId)); + if ( e ) + { + BlockInfo *b = e->second; + if ( memcmp(&pose,&b->mPose,sizeof(physx::PxMat44)) != 0 ) // if the pose has changed... + { + b->mPose = pose; + b->mChanged = true; + } + } + } + + /** + \brief Sets the global pose for the current debug-rendering context. This is preserved on the state stack. + + \param pos Sets the translation component + \param quat Sets the rotation component as a quat + */ + virtual void setPose(const float pos[3],const float quat[4]) + { + physx::PxTransform t(*(reinterpret_cast(pos)),*(reinterpret_cast(quat))); + physx::PxMat44 xform(t); + setPose(xform.front()); + } + + /** + \brief Sets the global pose position only, does not change the rotation. + + \param pos Sets the translation component + */ + virtual void setPosition(const float pos[3]) + { + setPosition( *(reinterpret_cast(pos))); + } + + /** + \brief Sets the global pose orientation only, does not change the position + + \param quat Sets the orientation of the global pose + */ + virtual void setOrientation(const float quat[3]) + { + setOrientation( *(reinterpret_cast(quat))); + } + + /** + \brief Sets the global pose back to identity + */ + virtual void setIdentityPose(void) + { + mCurrentState.mPose = NULL; + mCurrentState.mCurrentPose = physx::PxMat44(physx::PxIdentity); + mCurrentState.incrementChangeCount(); + } + + /** + \brief Sets the global pose for the current debug-rendering context. This is preserved on the state stack. + + \param pose Sets the pose from a position and quaternion rotation + */ + virtual void setPose(const physx::PxTransform &pose) + { + physx::PxMat44 m(pose); + setPose(m); + } + + /** + \brief Sets the global pose position only, does not change the rotation. + + \param position Sets the translation component + */ + virtual void setPosition(const physx::PxVec3 &position) + { + physx::PxMat44 m = mCurrentState.mCurrentPose; + m.setPosition(position); + setPose(m); + } + + /** + \brief Sets the global pose orientation only, does not change the position + + \param rot Sets the orientation of the global pose + */ + virtual void setOrientation(const physx::PxQuat &rot) + { + physx::PxMat44 m(rot); + m.setPosition(mCurrentState.mCurrentPose.getPosition()); + setPose(m); + } + + + virtual void setPose(const physx::PxMat44 &pose) + { + physx::PxMat44 id = physx::PxMat44(physx::PxIdentity); + if ( id.column0 != pose.column0 || + id.column1 != pose.column1 || + id.column2 != pose.column2 || + id.column3 != pose.column3 ) + { + mCurrentState.mCurrentPose = pose; + mCurrentState.mPose = &mCurrentState.mCurrentPose; + } + else + { + mCurrentState.mPose = NULL; + mCurrentState.mCurrentPose = physx::PxMat44(physx::PxIdentity); + } + mCurrentState.incrementChangeCount(); + } + + virtual const physx::PxMat44 * getPoseTyped(void) const + { + return &mCurrentState.mCurrentPose; + } + + virtual const float *getPose(void) const + { + return reinterpret_cast(&mCurrentState.mCurrentPose); + } + + + /* \brief Create an createDebugGraphDesc. This is the manual way of setting up a graph. Every parameter can + and must be customized when using this constructor. + */ + virtual DebugGraphDesc* createDebugGraphDesc(void) + { + DebugGraphDesc* dGDPtr = static_cast(PX_ALLOC(sizeof(DebugGraphDesc), PX_DEBUG_EXP("DebugGraphDesc"))); + new (dGDPtr ) DebugGraphDesc; + + dGDPtr->mNumPoints = 0; + dGDPtr->mPoints = NULL; + dGDPtr->mGraphXLabel = NULL; + dGDPtr->mGraphYLabel = NULL; + dGDPtr->mGraphColor = 0x00FF0000; + dGDPtr->mArrowColor = 0x0000FF00; + dGDPtr->mColorSwitchIndex = uint32_t(-1); + dGDPtr->mGraphMax = 0.0f; + dGDPtr->mGraphXPos = 0.0f; + dGDPtr->mGraphYPos = 0.0f; + dGDPtr->mGraphWidth = 0.0f; + dGDPtr->mGraphHeight = 0.0f; + dGDPtr->mCutOffLevel = 0.0f; + return(dGDPtr); + } + + virtual void releaseDebugGraphDesc(DebugGraphDesc *desc) + { + PX_FREE(desc); + } + + /** + \brief Create an createDebugGraphDesc using the minimal amount of work. This constructor provides for six custom + graphs to be simultaneously drawn on the display at one time numbered 0 to 5. The position, color, and size + of the graphs are automatically set based on the graphNum argument. + */ + #define LEFT_X (-0.9f) + #define RIGHT_X (+0.1f) + #define TOP_Y (+0.4f) + #define MID_Y (-0.2f) + #define BOTTOM_Y (-0.8f) + virtual DebugGraphDesc* createDebugGraphDesc(uint32_t graphNum,uint32_t dataCount,const float *dataArray, float maxY, char* xLabel, char* yLabel) + { + static struct + { + float xPos, yPos; + } graphData[MAX_GRAPHS] = + { + {LEFT_X, TOP_Y}, + {LEFT_X, MID_Y}, + {LEFT_X, BOTTOM_Y}, + {RIGHT_X, TOP_Y}, + {RIGHT_X, MID_Y}, + {RIGHT_X, BOTTOM_Y} + }; + PX_ASSERT(graphNum < MAX_GRAPHS); + DebugGraphDesc* dGDPtr = createDebugGraphDesc(); + + dGDPtr->mGraphColor = 0x00FF0000; + dGDPtr->mArrowColor = 0x0000FF00; + dGDPtr->mColorSwitchIndex = uint32_t(-1); + + // no cut off line by default + dGDPtr->mCutOffLevel = 0.0f; + dGDPtr->mNumPoints = dataCount; + dGDPtr->mPoints = dataArray; + dGDPtr->mGraphMax = maxY; + dGDPtr->mGraphXLabel = xLabel; + dGDPtr->mGraphYLabel = yLabel; + + dGDPtr->mGraphXPos = graphData[graphNum].xPos; + dGDPtr->mGraphYPos = graphData[graphNum].yPos;; + dGDPtr->mGraphWidth = GRAPH_WIDTH_DEFAULT; + dGDPtr->mGraphHeight = GRAPH_HEIGHT_DEFAULT; + + return(dGDPtr); + } + + virtual void debugGraph(const DebugGraphDesc& graphDesc) + { + DebugGraphStream d(graphDesc); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + } + + /** + \brief Set a debug color value by name. + */ + virtual void setDebugColor(RENDER_DEBUG::DebugColors::Enum colorEnum, uint32_t value) + { + if( colorEnum < RENDER_DEBUG::DebugColors::NUM_COLORS ) + { + colors[ colorEnum ] = value; + } + } + + /** + \brief Return a debug color value by name. + */ + virtual uint32_t getDebugColor(RENDER_DEBUG::DebugColors::Enum colorEnum) const + { + if( colorEnum < RENDER_DEBUG::DebugColors::NUM_COLORS ) + { + return colors[ colorEnum ]; + } + return 0; + } + + /** + \brief Return a debug color value by RGB inputs + */ + virtual uint32_t getDebugColor(float red, float green, float blue) const + { + union + { + uint8_t colorChars[4]; + uint32_t color; + }; + + colorChars[3] = 0xff; // alpha + colorChars[2] = uint8_t(red * 255); + colorChars[1] = uint8_t(green * 255); + colorChars[0] = uint8_t(blue * 255); + + return color; + } + + virtual void debugMessage(const char *fmt,...) + { + mCanSkip = false; + char wbuff[16384]; + wbuff[16383] = 0; + va_list arg; + va_start( arg, fmt ); + physx::shdfnd::vsnprintf(wbuff,sizeof(wbuff)-1, fmt, arg); + va_end(arg); + DebugMessage dt(wbuff); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + /** + \brief Render a set of instanced triangle meshes. + */ + virtual void renderTriangleMeshInstances(uint32_t meshId, // The ID of the previously created triangle mesh + uint32_t instanceCount, // The number of instances to render + const RENDER_DEBUG::RenderDebugInstance *instances) // The array of poses for each instance + { + DebugRenderTriangleMeshInstances dt(meshId,instanceCount,instances); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + + /** + \brief Create a debug texture based on a filename + + \param id The id associated with this custom texture, must be greater than 28; the reserved ids for detail textures + \param fname The name of the DDS file associated with this texture. + */ + virtual void createCustomTexture(uint32_t id,const char *fname) + { + mCanSkip = false; + DebugCreateCustomTexture dt(id,fname); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + + /** + \brief Create a triangle mesh that we can render. Assumes an indexed triangle mesh. User provides a *unique* id. If it is not unique, this will fail. + */ + virtual void createTriangleMesh(uint32_t meshId, // The unique mesh ID + uint32_t vcount, // The number of vertices in the triangle mesh + const RENDER_DEBUG::RenderDebugMeshVertex *meshVertices, // The array of vertices + uint32_t tcount, // The number of triangles (indices must contain tcount*3 values) + const uint32_t *indices) // The array of triangle mesh indices + { + mCanSkip = false; + DebugCreateTriangleMesh dt(meshId,vcount,meshVertices,tcount,indices); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + /** + \brief Refresh a sub-section of the vertices in a previously created triangle mesh. + + \param vcount This is the number of vertices to refresh. + \param refreshVertices This is an array of revised vertex data. + \param refreshIndices This is an array of indices which correspond to the original triangle mesh submitted. There should be one index for each vertex. + */ + virtual void refreshTriangleMeshVertices(uint32_t meshId, + uint32_t vcount, + const RenderDebugMeshVertex *refreshVertices, + const uint32_t *refreshIndices) + { + if ( vcount && refreshVertices && refreshIndices ) + { + DebugRefreshTriangleMeshVertices dt(meshId,vcount,refreshVertices,refreshIndices); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + } + + /** + \brief Release a previously created triangle mesh + */ + virtual void releaseTriangleMesh(uint32_t meshId) + { + mCanSkip = false; + DebugReleaseTriangleMesh d(meshId); + PostRenderDebug::postRenderDebug(&d,mCurrentState); + } + + /** + \brief Render a set of data points, either as wire-frame cross hairs or as a small solid instanced mesh. + + This callback provides the ability to (as rapidly as possible) render a large number of + + \param mode Determines what mode to render the point data + \param meshId The ID of the previously created triangle mesh if rendering in mesh mode + \param textureId1 The ID of the primary texture + \param textureTile1 The UV tiling rate of the primary texture + \param textureId2 The ID of the secondary texture + \param textureTile2 The UV tiling rate of the secondary texture + \param pointCount The number of points to render + \param points The array of points to render + */ + virtual void debugPoints(PointRenderMode mode, + uint32_t meshId, + uint32_t textureId1, + float textureTile1, + uint32_t textureId2, + float textureTile2, + uint32_t pointCount, + const float *points) + { + DebugRenderPoints dt(meshId,mode,textureId1,textureTile1,textureId2,textureTile2,pointCount,points); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + /** + \brief This method will produce a debug visualization of a convex hull; either as lines or solid triang;es depending on the current debug render state + + \param planeCount The number of planes in the convex hull + \param planes The array of plane equations in the convex hull + */ + virtual void debugConvexHull(uint32_t planeCount, + const float *planes) + { + DebugConvexHull dt(planeCount,planes); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + /** + \brief Implement this method to display lines output from the RenderDebug library + + \param lcount The number of lines to draw (vertex count=lines*2) + \param vertices The pairs of vertices for each line segment + \param useZ Whether or not these should be zbuffered + \param isScreenSpace Whether or not these are in homogeneous screen-space co-ordinates + */ + virtual void debugRenderLines(uint32_t lcount, + const RenderDebugVertex *vertices, + bool useZ, + bool isScreenSpace) + { + DebugRenderLines dt(lcount,vertices,useZ ? 1U : 0U,isScreenSpace ? 1U : 0U); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + /** + \brief Implement this method to display solid shaded triangles without any texture surce. + + \param tcount The number of triangles to render. (vertex count=tcount*2) + \param vertices The vertices for each triangle + \param useZ Whether or not these should be zbuffered + \param isScreenSpace Whether or not these are in homogeneous screen-space co-ordinates + */ + virtual void debugRenderTriangles(uint32_t tcount, + const RenderDebugSolidVertex *vertices, + bool useZ, + bool isScreenSpace) + { + DebugRenderTriangles dt(tcount,vertices,useZ ? 1U : 0U,isScreenSpace ? 1U : 0U); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + +private: + + void initColors() + { +#define INIT_COLOR( name, defVal, minVal, maxVal ) \ + colorsDefValue[ name ] = uint32_t(defVal); \ + colorsMinValue[ name ] = uint32_t(minVal); \ + colorsMaxValue[ name ] = uint32_t(maxVal); + + INIT_COLOR(RENDER_DEBUG::DebugColors::Default, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::PoseArrows, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::MeshStatic, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::MeshDynamic, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Shape, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Text0, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Text1, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::ForceArrowsLow, 0xffffff00, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::ForceArrowsNorm,0xff00ff00, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::ForceArrowsHigh,0xffff0000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Color0, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Color1, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Color2, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Color3, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Color4, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Color5, 0x00000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Red, 0xffff0000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Green, 0xff00ff00, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Blue, 0xff0000ff, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::DarkRed, 0xff800000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::DarkGreen, 0xff008000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::DarkBlue, 0xff000080, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::LightRed, 0xffff8080, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::LightGreen, 0xff80ff00, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::LightBlue, 0xff00ffff, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Purple, 0xffff00ff, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::DarkPurple, 0xff800080, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Yellow, 0xffffff00, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Orange, 0xffff8000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Gold, 0xff808000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Emerald, 0xff008080, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::White, 0xffffffff, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Black, 0xff000000, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::Gray, 0xff808080, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::LightGray, 0xffC0C0C0, 0, UINT32_MAX); + INIT_COLOR(RENDER_DEBUG::DebugColors::DarkGray, 0xff404040, 0, UINT32_MAX); +#undef INIT_COLOR + + memcpy( colors, colorsDefValue, sizeof(uint32_t) * RENDER_DEBUG::DebugColors::NUM_COLORS ); + } + + void releaseRenderDebug(void) + { + delete this; + } + + +//***************************************************** +//**** Non-typed version of methods +//***************************************************** + + virtual void debugPolygon(uint32_t pcount,const float *points) + { + debugPolygon(pcount,(reinterpret_cast(points))); + } + + virtual void debugLine(const float p1[3],const float p2[3]) + { + debugLine( *(reinterpret_cast(p1)),*(reinterpret_cast(p2))); + } + + virtual void debugGradientLine(const float p1[3],const float p2[3],const uint32_t &c1,const uint32_t &c2) + { + debugGradientLine(*(reinterpret_cast(p1)),*(reinterpret_cast(p2)),c1,c2); + } + + virtual void debugRay(const float p1[3],const float p2[3]) + { + debugRay(*(reinterpret_cast(p1)),*(reinterpret_cast(p2))); + } + + virtual void debugCylinder(const float p1[3],const float p2[3],float radius) + { + debugCylinder(*(reinterpret_cast(p1)),*(reinterpret_cast(p2)),radius); + } + + virtual void debugThickRay(const float p1[3],const float p2[3],float raySize=0.02f,bool includeArrow=true) + { + debugThickRay(*(reinterpret_cast(p1)),*(reinterpret_cast(p2)),raySize,includeArrow); + } + + virtual void debugPlane(const float normal[3],float dCoff,float radius1,float radius2) + { + physx::PxPlane p(normal[0],normal[1],normal[2],dCoff); + debugPlane(p,radius1,radius2); + } + + virtual void debugTri(const float p1[3],const float p2[3],const float p3[3]) + { + debugTri(*(reinterpret_cast(p1)),*(reinterpret_cast(p2)),*(reinterpret_cast(p3))); + } + + virtual void debugTriNormals(const float p1[3],const float p2[3],const float p3[3],const float n1[3],const float n2[3],const float n3[3]) + { + debugTriNormals(*(reinterpret_cast(p1)),*(reinterpret_cast(p2)),*(reinterpret_cast(p3)),*(reinterpret_cast(n1)),*(reinterpret_cast(n2)),*(reinterpret_cast(n3))); + } + + virtual void debugGradientTri(const float p1[3],const float p2[3],const float p3[3],const uint32_t &c1,const uint32_t &c2,const uint32_t &c3) + { + debugGradientTri(*(reinterpret_cast(p1)),*(reinterpret_cast(p2)),*(reinterpret_cast(p3)),c1,c2,c3); + } + + virtual void debugGradientTriNormals(const float p1[3],const float p2[3],const float p3[3],const float n1[3],const float n2[3],const float n3[3],const uint32_t &c1,const uint32_t &c2,const uint32_t &c3) + { + debugGradientTriNormals(*(reinterpret_cast(p1)),*(reinterpret_cast(p2)),*(reinterpret_cast(p3)),*(reinterpret_cast(n1)),*(reinterpret_cast(n2)),*(reinterpret_cast(n3)),c1,c2,c3); + } + + virtual void debugBound(const float bmin[3],const float bmax[3]) + { + physx::PxBounds3 b(*(reinterpret_cast(bmin)),*(reinterpret_cast(bmax))); + debugBound(b); + } + + virtual void debugSphere(const float pos[3],float radius,uint32_t subdivision) + { + debugSphere(*(reinterpret_cast(pos)),radius,subdivision); + } + + + virtual void debugCircle(const float center[3],float radius,uint32_t subdivision) + { + debugCircle(*(reinterpret_cast(center)),radius,subdivision); + } + + virtual void debugPoint(const float pos[3],float radius) + { + debugPoint(*(reinterpret_cast(pos)),radius); + } + + virtual void debugPoint(const float pos[3],const float scale[3]) + { + debugPoint(*(reinterpret_cast(pos)),*(reinterpret_cast(scale))); + } + + virtual void debugQuad(const float pos[3],const float scale[2],float orientation) + { + debugQuad(*(reinterpret_cast(pos)),*reinterpret_cast(scale),orientation); + } + + virtual void debugAxes(const float transform[16],float distance=0.1f,float brightness=1.0f,bool showXYZ=false,bool showRotation=false,uint32_t axisSwitch=4, DebugAxesRenderMode::Enum renderMode = DebugAxesRenderMode::DEBUG_AXES_RENDER_SOLID) + { + debugAxes(*(reinterpret_cast(transform)),distance,brightness,showXYZ,showRotation,axisSwitch,renderMode); + } + + virtual void debugArc(const float center[3],const float p1[3],const float p2[3],float arrowSize=0.1f,bool showRoot=false) + { + debugArc(*(reinterpret_cast(center)),*(reinterpret_cast(p1)),*(reinterpret_cast(p2)),arrowSize,showRoot); + } + + virtual void debugThickArc(const float center[3],const float p1[3],const float p2[3],float thickness=0.02f,bool showRoot=false) + { + debugThickArc(*(reinterpret_cast(center)),*(reinterpret_cast(p1)),*(reinterpret_cast(p2)),thickness,showRoot); + } + + virtual void debugText(const float pos[3],const char *fmt,...) + { + char wbuff[16384]; + wbuff[16383] = 0; + va_list arg; + va_start( arg, fmt ); + physx::shdfnd::vsnprintf(wbuff,sizeof(wbuff)-1, fmt, arg); + va_end(arg); + debugText(*(reinterpret_cast(pos)),"%s",wbuff); + } + + virtual void setViewMatrix(const float view[16]) + { + setViewMatrix(*(reinterpret_cast(view))); + } + + virtual void setProjectionMatrix(const float projection[16]) + { + setProjectionMatrix(*(reinterpret_cast(projection))); + } + + virtual void eulerToQuat(const float angles[3],float q[4]) // angles are in degrees. + { + eulerToQuat(*(reinterpret_cast(angles)),*(reinterpret_cast(q))); + } + + virtual int32_t beginDrawGroup(const float pose[16]) + { + return beginDrawGroup(*(reinterpret_cast(pose))); + } + + virtual void setDrawGroupPose(int32_t blockId,const float pose[16]) + { + setDrawGroupPose(blockId,*(reinterpret_cast(pose))); + } + + virtual void debugDetailedSphere(const float pos[3],float radius,uint32_t stepCount) + { + debugDetailedSphere(*(reinterpret_cast(pos)),radius,stepCount); + } + + virtual void setPose(const float pose[16]) + { + setPose(*(reinterpret_cast(pose))); + } + + virtual void debugFrustum(const float view[16],const float proj[16]) + { + debugFrustum( *(reinterpret_cast(view)),*(reinterpret_cast(proj))); + } + + +//***************************************************** +// ** Methods which get hooked back through the main parent interface. + /** + \brief Begins a file-playback session. Returns the number of recorded frames in the recording file. Zero if the file was not valid. + */ + virtual uint32_t setFilePlayback(const char *fileName) + { + return mRenderDebugHook->setFilePlayback(fileName); + } + + /** + \brief Set's the file playback to a specific frame. Returns true if successful. + */ + virtual bool setPlaybackFrame(uint32_t playbackFrame) + { + return mRenderDebugHook->setPlaybackFrame(playbackFrame); + } + + /** + \brief Returns the number of recorded frames in the debug render recording file. + */ + virtual uint32_t getPlaybackFrameCount(void) const + { + return mRenderDebugHook->getPlaybackFrameCount(); + } + + /** + \brief Stops the current recording playback. + */ + virtual void stopPlayback(void) + { + mRenderDebugHook->stopPlayback(); + } + + /** + \brief Do a 'try' lock on the global render debug mutex. This is simply provided as an optional convenience if you are accessing RenderDebug from multiple threads and want to prevent contention. + */ + virtual bool trylock(void) + { + return mRenderDebugHook->trylock(); + } + + /** + \brief Lock the global render-debug mutex to avoid thread contention. + */ + virtual void lock(void) + { + mRenderDebugHook->lock(); + } + + /** + \brief Unlock the global render-debug mutex + */ + virtual void unlock(void) + { + mRenderDebugHook->unlock(); + } + + /** + \brief Convenience method to return a unique mesh id number (simply a global counter to avoid clashing with other ids + */ + virtual uint32_t getMeshId(void) + { + return mRenderDebugHook->getMeshId(); + } + + /** + \brief Send a command from the server to the client. This could be any arbitrary console command, it can also be mouse drag events, debug visualization events, etc. + * the client receives this command in argc/argv format. + */ + virtual bool sendRemoteCommand(const char *fmt,...) + { + char buff[16384]; + buff[16383] = 0; + va_list arg; + va_start( arg, fmt ); + physx::shdfnd::vsnprintf(buff,sizeof(buff)-1, fmt, arg); + va_end(arg); + return mRenderDebugHook->sendRemoteCommand("%s",buff); + } + + /** + \brief If running in client mode, poll this method to retrieve any pending commands from the server. If it returns NULL then there are no more commands. + */ + virtual const char ** getRemoteCommand(uint32_t &argc) + { + return mRenderDebugHook->getRemoteCommand(argc); + } + + /** + \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 An arbitrary command associated with this data transfer, for example this could indicate a remote file request. + \param resourceName An arbitrary id 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) + { + return mRenderDebugHook->sendRemoteResource(nameSpace,resourceName,data,dlen); + } + + + /** + \brief Retrieves a block of remotely transmitted binary data. + + \param nameSpace A a reference to a pointer which will store the namespace (type) 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 resource name 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) + { + return mRenderDebugHook->getRemoteResource(nameSpace,resourceName,dlen,remoteIsBigEndian); + } + + /** + \brief This function allows you to request a file from the remote machine by name. If successful it will be returned via 'getRemoteData' + + \param command The command field associated with this request which will be returned by 'getRemoteData' + \param fileName The filename 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 *command, + const char *fileName) + { + return mRenderDebugHook->requestRemoteResource(command,fileName); + } + + /** + \brief Report what 'Run' mode we are operation gin. + */ + virtual RenderDebug::RunMode getRunMode(void) + { + return mRenderDebugHook->getRunMode(); + } + + /** + \brief Returns true if we still have a valid connection to the server. + */ + virtual bool isConnected(void) const + { + return mRenderDebugHook->isConnected(); + } + + /** + \brief Returns the current synchronized frame between client/server communications. Returns zero if no active connection exists. + */ + virtual uint32_t getCommunicationsFrame(void) const + { + return mRenderDebugHook->getCommunicationsFrame(); + } + + virtual const char *getRemoteApplicationName(void) + { + return mRenderDebugHook->getRemoteApplicationName(); + } + + /** + \brief Returns the optional typed methods for various render debug routines. + */ + virtual RenderDebugTyped *getRenderDebugTyped(void) + { + return mRenderDebugHook->getRenderDebugTyped(); + } + + /** + \brief Release the render debug class + */ + virtual void release(void) + { + mRenderDebugHook->release(); + } + + virtual bool render(float dtime,RENDER_DEBUG::RenderDebugInterface *iface) + { + return mRenderDebugHook->render(dtime,iface); + } + + /** + \brief register a digital input event (maps to windows keyboard commands) + + \param eventId The eventId for this input event; if it is a custom event it must be greater than NUM_SAMPLE_FRAMEWORK_INPUT_EVENT_IDS + \param inputId This the pre-defined keyboard code for this input event. + */ + virtual void registerDigitalInputEvent(InputEventIds::Enum eventId,InputIds::Enum inputId) + { + mCanSkip = false; + DebugRegisterInputEvent dt(true,eventId,0.0f,inputId); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + virtual void unregisterInputEvent(InputEventIds::Enum eventId) + { + mCanSkip = false; + DebugUnregisterInputEvent dt(eventId); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + + /** + \brief register a digital input event (maps to windows keyboard commands) + + \param eventId The eventId for this input event; if it is a custom event it must be greater than NUM_SAMPLE_FRAMEWORK_INPUT_EVENT_IDS + \param sensitivity The sensitivity value associated with this anaglog devent; default value is 1.0 + \param inputId This the pre-defined analog code for this input event. + */ + virtual void registerAnalogInputEvent(InputEventIds::Enum eventId,float sensitivity,InputIds::Enum inputId) + { + mCanSkip = false; + DebugRegisterInputEvent dt(false,eventId,sensitivity,inputId); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + /** + \brief Reset all input events to an empty state + */ + virtual void resetInputEvents(void) + { + mCanSkip = false; + DebugPrimitiveU32 dt(DebugCommand::DEBUG_RESET_INPUT_EVENTS,0); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + + virtual void sendInputEvent(const InputEvent &ev) + { + if ( mRenderDebugHook ) + { + mRenderDebugHook->sendInputEvent(ev); + } + } + + /** + \brief Returns any incoming input event for processing purposes + */ + virtual const InputEvent *getInputEvent(bool flush) + { + const InputEvent *e = NULL; + + if ( mRenderDebugHook ) + { + e = mRenderDebugHook->getInputEvent(flush); + } + return e; + } + + /** + \brief Set the base file name to record communications tream; 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) + { + bool ret = false; + if ( mRenderDebugHook ) + { + ret = mRenderDebugHook->setStreamFilename(fileName); + } + 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) + { + bool ret = false; + if ( mRenderDebugHook ) + { + ret = mRenderDebugHook->setStreamPlayback(fileName); + } + return ret; + } + + /** + \brief Special case command that affects how the server processes the previous frame of data. + + \return Returns true if it is safe to skip this frame of data, false if there are required commands that must be executed. + */ + virtual bool trySkipFrame(void) + { + if ( mCanSkip ) + { + DebugPrimitiveU32 dt(DebugCommand::DEBUG_SKIP_FRAME,0); + PostRenderDebug::postRenderDebug(&dt,mCurrentState); + } + return mCanSkip; + } + + bool mCanSkip; + RenderDebugHook *mRenderDebugHook; + uint32_t mUpdateCount; + ProcessRenderDebug *mProcessRenderDebug; + RenderState mCurrentState; + uint32_t mStackIndex; + RenderState mRenderStateStack[RENDER_STATE_STACK_SIZE]; + mutable float mViewMatrix44[16]; + mutable float mProjectionMatrix44[16]; + mutable float mViewProjectionMatrix44[16]; + physx::PxVec3 mEyePos; + //Colors for debug rendering purposes + uint32_t colors[RENDER_DEBUG::DebugColors::NUM_COLORS]; + uint32_t colorsMinValue[RENDER_DEBUG::DebugColors::NUM_COLORS]; + uint32_t colorsMaxValue[RENDER_DEBUG::DebugColors::NUM_COLORS]; + uint32_t colorsDefValue[RENDER_DEBUG::DebugColors::NUM_COLORS]; + + uint32_t mBlockIndex; + physx::shdfnd::HashMap mBlocksHash; + physx::shdfnd::Pool< BlockInfo > mBlocks; + float mFrameTime; + bool mOwnProcess; + +}; + +DebugGraphStream::DebugGraphStream(const DebugGraphDesc &d) : DebugPrimitive(DebugCommand::DEBUG_GRAPH) +{ + physx::PsMemoryBuffer mb; + mb.setEndianMode(physx::PxFileBuf::ENDIAN_NONE); + nvidia::StreamIO stream(mb,0); + + mSize = 0; + stream << mCommand; + stream << mSize; + stream << d.mNumPoints; + stream.storeString(d.mGraphXLabel ? d.mGraphXLabel : "",true); + stream.storeString(d.mGraphYLabel ? d.mGraphYLabel : "",true); + + mb.alignWrite(4); + + for (uint32_t i=0; i(mBuffer); + dest[1] = mSize; + + mAllocated = true; +} + +DebugCreateTriangleMesh::~DebugCreateTriangleMesh(void) +{ + if ( mAllocated ) + { + PX_FREE(mBuffer); + } +} + + +DebugRefreshTriangleMeshVertices::DebugRefreshTriangleMeshVertices(uint32_t meshId, + uint32_t vcount, // The number of vertices in the triangle mesh + const RENDER_DEBUG::RenderDebugMeshVertex *meshVertices, // The array of vertices + const uint32_t *indices) : DebugPrimitive(DebugCommand::DEBUG_REFRESH_TRIANGLE_MESH_VERTICES) +{ + physx::PsMemoryBuffer mb; + mb.setEndianMode(physx::PxFileBuf::ENDIAN_NONE); + nvidia::StreamIO stream(mb,0); + + mSize = 0; + stream << mCommand; + stream << mSize; + stream << meshId; + stream << vcount; + + if ( vcount ) + { + mb.write(meshVertices,sizeof(RENDER_DEBUG::RenderDebugMeshVertex)*vcount); + } + + if ( vcount ) + { + mb.write(indices,sizeof(uint32_t)*vcount); + } + + mBuffer = mb.getWriteBufferOwnership(mSize); + + uint32_t *dest = reinterpret_cast(mBuffer); + dest[1] = mSize; + + mAllocated = true; +} + +DebugRefreshTriangleMeshVertices::~DebugRefreshTriangleMeshVertices(void) +{ + if ( mAllocated ) + { + PX_FREE(mBuffer); + } +} + + +DebugRenderTriangleMeshInstances::DebugRenderTriangleMeshInstances(uint32_t meshId, + uint32_t instanceCount, + const RENDER_DEBUG::RenderDebugInstance *instances) : DebugPrimitive(DebugCommand::DEBUG_RENDER_TRIANGLE_MESH_INSTANCES) +{ + physx::PsMemoryBuffer mb; + mb.setEndianMode(physx::PxFileBuf::ENDIAN_NONE); + nvidia::StreamIO stream(mb,0); + + mSize = 0; + stream << mCommand; + stream << mSize; + stream << meshId; + stream << instanceCount; + + if ( instanceCount ) + { + mb.write(instances,sizeof(RENDER_DEBUG::RenderDebugInstance)*instanceCount); + } + + mBuffer = mb.getWriteBufferOwnership(mSize); + + uint32_t *dest = reinterpret_cast(mBuffer); + dest[1] = mSize; + + mAllocated = true; +} + +DebugRenderTriangleMeshInstances::~DebugRenderTriangleMeshInstances(void) +{ + if ( mAllocated ) + { + PX_FREE(mBuffer); + } +} + +DebugConvexHull::DebugConvexHull(uint32_t planeCount,const float *planes) : DebugPrimitive(DebugCommand::DEBUG_CONVEX_HULL) +{ + physx::PsMemoryBuffer mb; + mb.setEndianMode(physx::PxFileBuf::ENDIAN_NONE); + nvidia::StreamIO stream(mb,0); + + mSize = 0; + stream << mCommand; + stream << mSize; + stream << planeCount; + if ( planeCount ) + { + mb.write(planes,sizeof(float)*4*planeCount); + } + mBuffer = mb.getWriteBufferOwnership(mSize); + + uint32_t *dest = reinterpret_cast(mBuffer); + dest[1] = mSize; + + mAllocated = true; +} + +DebugConvexHull::~DebugConvexHull(void) +{ + if ( mAllocated ) + { + PX_FREE(mBuffer); + } +} + +DebugRenderPoints::DebugRenderPoints(uint32_t meshId, + PointRenderMode mode, + uint32_t textureId1, + float textureTile1, + uint32_t textureId2, + float textureTile2, + uint32_t pointCount, + const float *points) : DebugPrimitive(DebugCommand::DEBUG_RENDER_POINTS) +{ + physx::PsMemoryBuffer mb; + mb.setEndianMode(physx::PxFileBuf::ENDIAN_NONE); + nvidia::StreamIO stream(mb,0); + + mSize = 0; + stream << mCommand; + stream << mSize; + stream << meshId; + stream << uint32_t(mode); + stream << textureId1; + stream << textureTile1; + stream << textureId2; + stream << textureTile2; + stream << pointCount; + + if ( pointCount ) + { + mb.write(points,sizeof(float)*3*pointCount); + } + + mBuffer = mb.getWriteBufferOwnership(mSize); + + uint32_t *dest = reinterpret_cast(mBuffer); + dest[1] = mSize; + + mAllocated = true; +} + +DebugRenderPoints::~DebugRenderPoints(void) +{ + if ( mAllocated ) + { + PX_FREE(mBuffer); + } +} + +DebugRenderLines::DebugRenderLines(uint32_t lcount, + const RenderDebugVertex *vertices, + uint32_t useZ, + uint32_t isScreenSpace) : DebugPrimitive(DebugCommand::DEBUG_RENDER_LINES) +{ + physx::PsMemoryBuffer mb; + mb.setEndianMode(physx::PxFileBuf::ENDIAN_NONE); + nvidia::StreamIO stream(mb,0); + + mSize = 0; + stream << mCommand; + stream << mSize; + stream << lcount; + stream << useZ; + stream << isScreenSpace; + + if ( lcount ) + { + mb.write(vertices,sizeof(RenderDebugVertex)*2*lcount); + } + + mBuffer = mb.getWriteBufferOwnership(mSize); + + uint32_t *dest = reinterpret_cast(mBuffer); + dest[1] = mSize; + + mAllocated = true; +} + +DebugRenderLines::~DebugRenderLines(void) +{ + if ( mAllocated ) + { + PX_FREE(mBuffer); + } +} + + +DebugRenderTriangles::DebugRenderTriangles(uint32_t tcount, + const RenderDebugSolidVertex *vertices, + uint32_t useZ, + uint32_t isScreenSpace) : DebugPrimitive(DebugCommand::DEBUG_RENDER_TRIANGLES) +{ + physx::PsMemoryBuffer mb; + mb.setEndianMode(physx::PxFileBuf::ENDIAN_NONE); + nvidia::StreamIO stream(mb,0); + + mSize = 0; + stream << mCommand; + stream << mSize; + stream << tcount; + stream << useZ; + stream << isScreenSpace; + + if ( tcount ) + { + mb.write(vertices,sizeof(RenderDebugSolidVertex)*3*tcount); + } + + mBuffer = mb.getWriteBufferOwnership(mSize); + + uint32_t *dest = reinterpret_cast(mBuffer); + dest[1] = mSize; + + mAllocated = true; +} + +DebugRenderTriangles::~DebugRenderTriangles(void) +{ + if ( mAllocated ) + { + PX_FREE(mBuffer); + } +} + + + + +// + +RenderDebugImpl * createInternalRenderDebug(ProcessRenderDebug *process,RenderDebugHook *renderDebugHook) +{ + InternalRenderDebug *m = PX_NEW(InternalRenderDebug)(process,renderDebugHook); + return static_cast< RenderDebugImpl *>(m); +} + + + +} // end of namespace -- cgit v1.2.3