/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "stdafx.h" #include "EMsgBuffer.h" #include #include #include void AngleToUL(ANGLE3D &Angle,ULONG &ulResult) { Quaternion qQuat; FLOAT3D Axis; float fRotAngle; ANGLE3D AxisAngles; UBYTE ubDir; UWORD swAngle; qQuat.FromEuler(Angle); qQuat.ToAxisAngle(Axis,fRotAngle); Axis.Normalize(); DirectionVectorToAngles(Axis,AxisAngles); ubDir = (UBYTE) (AxisAngles(1)/360*255); ulResult = ubDir; ubDir = (UBYTE) (AxisAngles(2)/90*127); ulResult = ulResult << 8; ulResult |= ubDir; swAngle = (UWORD) (SWORD) (fRotAngle * 180); // after rounding, angle is precise up to 1/180 degrees (65536/360 ~ 180) ulResult = (ulResult << 16) | swAngle; }; void ULToAngle(ULONG &ulResult,ANGLE3D &Angle) { Quaternion qQuat; FLOAT3D Axis; float fRotAngle; ANGLE3D AxisAngles; UBYTE ubDir; UWORD swAngle; Matrix mRotMatrix; swAngle = ulResult & 0x0000FFFF; fRotAngle = swAngle / 180.0f; ulResult = ulResult >> 16; ubDir = ulResult & 0x000000FF; AxisAngles(2) = ((FLOAT) ubDir)*90/127; ulResult = ulResult >> 8; ubDir = ulResult & 0x000000FF; AxisAngles(1) = ((FLOAT) ubDir)*360/255; AxisAngles(3) = 0; AnglesToDirectionVector(AxisAngles,Axis); qQuat.FromAxisAngle(Axis,fRotAngle); qQuat.ToMatrix(mRotMatrix); DecomposeRotationMatrixNoSnap(Angle,mRotMatrix); }; void CEntityMessage::WritePlacement(ULONG &ulEntityID,CPlacement3D &plPlacement) { UBYTE *pubMarker; ULONG ulShrunkAngle; SWORD swH,swP,swB; em_ulType = EMT_SETPLACEMENT; em_ubSize = sizeof(FLOAT3D) + sizeof(ULONG); em_ulEntityID = ulEntityID; swH = (SWORD) ((plPlacement.pl_OrientationAngle(1)+180)*5); swP = (SWORD) ((plPlacement.pl_OrientationAngle(2)+90)*5); swB = (SWORD) ((plPlacement.pl_OrientationAngle(3)+180)*5); ulShrunkAngle = ((((ULONG) swH) & 0x000007FF) << 21); ulShrunkAngle |= ((((ULONG) swP) & 0x000003FF) << 11); ulShrunkAngle |= (((ULONG) swB) & 0x000007FF); pubMarker = em_aubMessage; memcpy(pubMarker,&(plPlacement.pl_PositionVector(1)),sizeof(FLOAT3D)); pubMarker += sizeof(FLOAT3D); memcpy(pubMarker,&ulShrunkAngle,sizeof(ULONG)); }; void CEntityMessage::ReadPlacement(ULONG &ulEntityID,CPlacement3D &plPlacement) { ASSERT (em_ulType == EMT_SETPLACEMENT); UBYTE *pubMarker; ULONG ulShrunkAngle; SWORD swH,swP,swB; ulEntityID = em_ulEntityID; pubMarker = em_aubMessage; memcpy(&(plPlacement.pl_PositionVector(1)),pubMarker,sizeof(FLOAT3D)); pubMarker += sizeof(FLOAT3D); memcpy(&ulShrunkAngle,pubMarker,sizeof(ULONG)); swB = (SWORD) ulShrunkAngle & 0x000007FF; swP = (SWORD) (ulShrunkAngle >> 11) & 0x000003FF; swH = (SWORD) (ulShrunkAngle >> 21) & 0x000007FF; plPlacement.pl_OrientationAngle(1) = ((float)swH) / 5 - 180; plPlacement.pl_OrientationAngle(2) = ((float)swP) / 5 - 90; plPlacement.pl_OrientationAngle(3) = ((float)swB) / 5 - 180; }; void CEntityMessage::WriteEntityEvent(ULONG &ulEntityID,UWORD &uwEventCode,void* pvEventData,UWORD &uwDataSize) { UBYTE *pubMarker; em_ulType = EMT_EVENT; em_ubSize = sizeof(UWORD) + uwDataSize; em_ulEntityID = ulEntityID; pubMarker = em_aubMessage; memcpy(pubMarker,&uwEventCode,sizeof(SLONG)); pubMarker += sizeof(UWORD); memcpy(pubMarker,pvEventData,uwDataSize); }; void CEntityMessage::ReadEntityEvent(ULONG &ulEntityID,UWORD &uwEventCode,void* pvEventData,UWORD &uwDataSize) { ASSERT (em_ulType == EMT_EVENT); UBYTE *pubMarker; pubMarker = em_aubMessage; memcpy(&uwEventCode,pubMarker,sizeof(SLONG)); pubMarker += sizeof(UWORD); uwDataSize = em_ubSize - sizeof(ULONG) - sizeof(UWORD); memcpy(pvEventData,pubMarker,uwDataSize); }; void CEntityMessage::WriteEntityCreate(ULONG &ulEntityID,CPlacement3D &plPlacement,UWORD &uwEntityClassID,UWORD &uwEventCode,void* pvEventData,UWORD &uwDataSize) { UBYTE *pubMarker; ULONG ulShrunkAngle; SWORD swH,swP,swB; em_ulType = EMT_CREATE; em_ubSize = sizeof(FLOAT3D) + sizeof(ULONG) + sizeof(UWORD) + sizeof(UWORD) + uwDataSize; em_ulEntityID = ulEntityID; swH = (SWORD) ((plPlacement.pl_OrientationAngle(1)+180)*5); swP = (SWORD) ((plPlacement.pl_OrientationAngle(2)+90)*5); swB = (SWORD) ((plPlacement.pl_OrientationAngle(3)+180)*5); ulShrunkAngle = ((((ULONG) swH) & 0x000007FF) << 21); ulShrunkAngle |= ((((ULONG) swP) & 0x000003FF) << 11); ulShrunkAngle |= (((ULONG) swB) & 0x000007FF); pubMarker = em_aubMessage; memcpy(pubMarker,&(plPlacement.pl_PositionVector(1)),sizeof(FLOAT3D)); pubMarker += sizeof(FLOAT3D); memcpy(pubMarker,&ulShrunkAngle,sizeof(ULONG)); pubMarker += sizeof(ULONG); memcpy(pubMarker,&uwEntityClassID,sizeof(UWORD)); pubMarker += sizeof(UWORD); memcpy(pubMarker,&uwEventCode,sizeof(UWORD)); pubMarker += sizeof(UWORD); memcpy(pubMarker,pvEventData,uwDataSize); }; void CEntityMessage::ReadEntityCreate(ULONG &ulEntityID,CPlacement3D &plPlacement,UWORD &uwEntityClassID,UWORD &uwEventCode,void* pvEventData,UWORD &uwDataSize) { ASSERT (em_ulType == EMT_CREATE); UBYTE *pubMarker; ULONG ulShrunkAngle; SWORD swH,swP,swB; ulEntityID = em_ulEntityID; pubMarker = em_aubMessage; memcpy(&(plPlacement.pl_PositionVector(1)),pubMarker,sizeof(FLOAT3D)); pubMarker += sizeof(FLOAT3D); memcpy(&ulShrunkAngle,pubMarker,sizeof(ULONG)); swB = (SWORD) ulShrunkAngle & 0x000007FF; swP = (SWORD) (ulShrunkAngle >> 11) & 0x000003FF; swH = (SWORD) (ulShrunkAngle >> 21) & 0x000007FF; plPlacement.pl_OrientationAngle(1) = ((float)swH) / 5 - 180; plPlacement.pl_OrientationAngle(2) = ((float)swP) / 5 - 90; plPlacement.pl_OrientationAngle(3) = ((float)swB) / 5 - 180; pubMarker += sizeof(ULONG); memcpy(&uwEntityClassID,pubMarker,sizeof(UWORD)); pubMarker += sizeof(UWORD); memcpy(&uwEventCode,pubMarker,sizeof(UWORD)); pubMarker += sizeof(UWORD); uwDataSize = em_ubSize - sizeof(FLOAT3D) - sizeof(ULONG) - sizeof(UWORD) - sizeof(UWORD); memcpy(pubMarker,pvEventData,uwDataSize); }; void CEntityMessage::WriteEntityDestroy(ULONG &ulEntityID) { em_ulType = EMT_DESTROY; em_ubSize = 0; em_ulEntityID = ulEntityID; }; void CEntityMessage::ReadEntityDestroy(ULONG &ulEntityID) { ASSERT (em_ulType == EMT_DESTROY); ulEntityID = em_ulEntityID; }; void CEntityMessage::WriteEntityCopy(ULONG &ulSourceEntityID,ULONG &ulTargetEntityID,CPlacement3D &plPlacement,UWORD &uwEventCode,void* pvEventData,UWORD &uwDataSize) { UBYTE *pubMarker; ULONG ulShrunkAngle; SWORD swH,swP,swB; em_ulType = EMT_COPY; em_ubSize = sizeof(ULONG) + sizeof(FLOAT3D) + sizeof(ULONG) + sizeof(UWORD) + uwDataSize; em_ulEntityID = ulSourceEntityID; swH = (SWORD) ((plPlacement.pl_OrientationAngle(1)+180)*5); swP = (SWORD) ((plPlacement.pl_OrientationAngle(2)+90)*5); swB = (SWORD) ((plPlacement.pl_OrientationAngle(3)+180)*5); ulShrunkAngle = ((((ULONG) swH) & 0x000007FF) << 21); ulShrunkAngle |= ((((ULONG) swP) & 0x000003FF) << 11); ulShrunkAngle |= (((ULONG) swB) & 0x000007FF); pubMarker = em_aubMessage; memcpy(pubMarker,&ulTargetEntityID,sizeof(ULONG)); pubMarker += sizeof(ULONG); memcpy(pubMarker,&(plPlacement.pl_PositionVector(1)),sizeof(FLOAT3D)); pubMarker += sizeof(FLOAT3D); memcpy(pubMarker,&ulShrunkAngle,sizeof(ULONG)); pubMarker += sizeof(ULONG); memcpy(pubMarker,&uwEventCode,sizeof(SLONG)); pubMarker += sizeof(UWORD); memcpy(pubMarker,pvEventData,uwDataSize); }; void CEntityMessage::ReadEntityCopy(ULONG &ulSourceEntityID,ULONG &ulTargetEntityID,CPlacement3D &plPlacement,UWORD &uwEventCode,void* pvEventData,UWORD &uwDataSize) { ASSERT (em_ulType == EMT_COPY); UBYTE *pubMarker; ULONG ulShrunkAngle; SWORD swH,swP,swB; ulSourceEntityID = em_ulEntityID; pubMarker = em_aubMessage; memcpy(&ulTargetEntityID,pubMarker,sizeof(ULONG)); pubMarker += sizeof(ULONG); memcpy(&(plPlacement.pl_PositionVector(1)),pubMarker,sizeof(FLOAT3D)); pubMarker += sizeof(FLOAT3D); memcpy(&ulShrunkAngle,pubMarker,sizeof(ULONG)); swB = (SWORD) ulShrunkAngle & 0x000007FF; swP = (SWORD) (ulShrunkAngle >> 11) & 0x000003FF; swH = (SWORD) (ulShrunkAngle >> 21) & 0x000007FF; plPlacement.pl_OrientationAngle(1) = ((float)swH) / 5 - 180; plPlacement.pl_OrientationAngle(2) = ((float)swP) / 5 - 90; plPlacement.pl_OrientationAngle(3) = ((float)swB) / 5 - 180; pubMarker += sizeof(ULONG); memcpy(&uwEventCode,pubMarker,sizeof(SLONG)); pubMarker += sizeof(UWORD); uwDataSize = em_ubSize - sizeof(ULONG) - sizeof(FLOAT3D) - sizeof(ULONG) - sizeof(UWORD); memcpy(pubMarker,pvEventData,uwDataSize); }; CEMsgBuffer::CEMsgBuffer() { emb_uwNumTickMarkers = 0; emb_iFirstTickMarker = 0; emb_iCurrentTickMarker = 0; emb_fCurrentTickTime = -1; for (int i=0;i 0); ULONG ulTemp; int iTickMarker; ulTemp = emEntityMessage.em_ulEntityID | (emEntityMessage.em_ulType << 24); WriteBytes(&(ulTemp),sizeof(ULONG)); WriteBytes(&(emEntityMessage.em_ubSize),sizeof(emEntityMessage.em_ubSize)); if (emEntityMessage.em_ubSize > 0) { WriteBytes(emEntityMessage.em_aubMessage,emEntityMessage.em_ubSize); } iTickMarker = emb_iCurrentTickMarker-1; if (iTickMarker < 0) iTickMarker += MAX_TICKS_KEPT; emb_atmTickMarkers[iTickMarker].tm_uwNumMessages++; }; int CEMsgBuffer::ReadMessage(CEntityMessage &emEntityMessage) { ULONG ulTemp; if (bu_slReadOffset == bu_slWriteOffset) { return EMB_ERR_BUFFER_EMPTY; } ReadBytes(&(ulTemp),sizeof(ULONG)); emEntityMessage.em_ulType = ulTemp >> 24; emEntityMessage.em_ulEntityID = ulTemp & 0x007FFFFF; ReadBytes(&(emEntityMessage.em_ubSize),sizeof(emEntityMessage.em_ubSize)); if (emEntityMessage.em_ubSize > 0) { ReadBytes(emEntityMessage.em_aubMessage,emEntityMessage.em_ubSize); } return EMB_SUCCESS_OK; }; int CEMsgBuffer::PeekMessageAtOffset(CEntityMessage &emEntityMessage,SLONG &slTickOffset) { ASSERT(slTickOffset >= 0 && slTickOffset <= bu_slSize); ULONG ulTemp; PeekBytesAtOffset(&(ulTemp),sizeof(ULONG),slTickOffset); emEntityMessage.em_ulType = ulTemp >> 24; emEntityMessage.em_ulEntityID = ulTemp & 0x007FFFFF; PeekBytesAtOffset(&(emEntityMessage.em_ubSize),sizeof(emEntityMessage.em_ubSize),slTickOffset); if (emEntityMessage.em_ubSize > 0) { PeekBytesAtOffset(emEntityMessage.em_aubMessage,emEntityMessage.em_ubSize,slTickOffset); } return EMB_SUCCESS_OK; }; int CEMsgBuffer::StartNewTick(float fTickTime) { if (emb_uwNumTickMarkers >= MAX_TICKS_KEPT) { return EMB_ERR_MAX_TICKS; } emb_atmTickMarkers[emb_iCurrentTickMarker].tm_fTickTime = fTickTime; emb_atmTickMarkers[emb_iCurrentTickMarker].tm_slTickOffset = bu_slWriteOffset; emb_atmTickMarkers[emb_iCurrentTickMarker].tm_ubAcknowledgesExpected = 0; emb_atmTickMarkers[emb_iCurrentTickMarker].tm_uwNumMessages = 0; emb_uwNumTickMarkers++; emb_iCurrentTickMarker++; emb_iCurrentTickMarker %= MAX_TICKS_KEPT; return EMB_SUCCESS_OK; }; int CEMsgBuffer::SetCurrentTick(float fTickTime) { int iErr; INDEX iTickIndex; iErr = GetTickIndex(fTickTime,iTickIndex); if (iErr != EMB_SUCCESS_OK) { return iErr; } emb_iCurrentTickMarker = iTickIndex; return EMB_SUCCESS_OK; }; int CEMsgBuffer::GetTickIndex(float fTickTime,INDEX &iTickIndex) { INDEX iTickMarker; // 0.025 should be _pTimer->TickQuantum/2 for (int i=0;iTickQuantum/2 for (int i=0;i 0) { fNextTickTime = emb_atmTickMarkers[0].tm_fTickTime; return EMB_SUCCESS_OK; } else { return EMB_ERR_NOT_IN_BUFFER; } } if (fTickTime < emb_atmTickMarkers[emb_iFirstTickMarker].tm_fTickTime) { fNextTickTime = emb_atmTickMarkers[emb_iFirstTickMarker].tm_fTickTime; return SUCCESS_OK; }; iErr = GetTickIndex(fTickTime,iTickIndex); if (iErr != EMB_SUCCESS_OK) { return iErr; } iTickIndex = (iTickIndex + 1) % MAX_TICKS_KEPT; fNextTickTime = emb_atmTickMarkers[iTickIndex].tm_fTickTime; return EMB_SUCCESS_OK; }; int CEMsgBuffer::RequestTickAcknowledge(float fTickTime,UBYTE ubNumAcknowledges) { ASSERT (fTickTime >= 0); INDEX iTickIndex; int iErr; iErr = GetTickIndex(fTickTime,iTickIndex); if (iErr == EMB_SUCCESS_OK) { emb_atmTickMarkers[iTickIndex].tm_ubAcknowledgesExpected += ubNumAcknowledges; return EMB_SUCCESS_OK; } return iErr; }; int CEMsgBuffer::ReceiveTickAcknowledge(float fTickTime) { ASSERT (fTickTime >= 0); INDEX iTickIndex; INDEX iFirst; int iErr; int iNumMark = emb_uwNumTickMarkers; iErr = GetTickIndex(fTickTime,iTickIndex); if (iErr == EMB_SUCCESS_OK) { iFirst = emb_iFirstTickMarker; emb_atmTickMarkers[iFirst].tm_ubAcknowledgesExpected--; while (iFirst!=iTickIndex) { iFirst++; iFirst%=MAX_TICKS_KEPT; emb_atmTickMarkers[iFirst].tm_ubAcknowledgesExpected--; } iFirst = emb_iFirstTickMarker; if (emb_atmTickMarkers[iFirst].tm_ubAcknowledgesExpected == 0 && iNumMark != 0) { while (emb_atmTickMarkers[iFirst].tm_ubAcknowledgesExpected == 0 && iNumMark != 0) { if (iNumMark > 0) { iNumMark--; iFirst++; iFirst %= MAX_TICKS_KEPT; } } MoveToStartOfTick(emb_atmTickMarkers[iFirst].tm_fTickTime); } return EMB_SUCCESS_OK; } return iErr; }; // does not advance the read offset - access is random, not sequential int CEMsgBuffer::ReadTick(float fTickTime,const void *pv, SLONG &slSize) { ASSERT (slSize>0); ASSERT (pv != NULL); ASSERT (fTickTime >= 0); int iErr; INDEX iTickIndex,iNextTickIndex; iErr = GetTickIndex(fTickTime,iTickIndex); if (iErr != EMB_SUCCESS_OK) { return iErr; } if (iTickIndex >= (emb_iFirstTickMarker + emb_uwNumTickMarkers - 1)) { return EMB_ERR_TICK_NOT_COMPLETE; } iNextTickIndex = (iTickIndex + 1) % MAX_TICKS_KEPT; SLONG slTickSize = emb_atmTickMarkers[iNextTickIndex].tm_slTickOffset - emb_atmTickMarkers[iTickIndex].tm_slTickOffset; // if not wrapping if ( slTickSize > 0) { if (slSize < slTickSize) { return EMB_ERR_BUFFER_TOO_SMALL; } slSize = slTickSize; memcpy((UBYTE*)pv,bu_pubBuffer+emb_atmTickMarkers[iTickIndex].tm_slTickOffset,slTickSize); } else { if (slSize < (bu_slSize - emb_atmTickMarkers[iTickIndex].tm_slTickOffset) + emb_atmTickMarkers[iNextTickIndex].tm_slTickOffset-1) { return EMB_ERR_BUFFER_TOO_SMALL; } slSize = (bu_slSize - emb_atmTickMarkers[iTickIndex].tm_slTickOffset) + emb_atmTickMarkers[iNextTickIndex].tm_slTickOffset; // copy data from the start of this ick to the end of the bufer memcpy((UBYTE*)pv,bu_pubBuffer+emb_atmTickMarkers[iTickIndex].tm_slTickOffset,bu_slSize - emb_atmTickMarkers[iTickIndex].tm_slTickOffset); // copy datafrom the start of the buffer to the start of next tick memcpy(((UBYTE*)pv)+bu_slSize - emb_atmTickMarkers[iTickIndex].tm_slTickOffset,bu_pubBuffer,emb_atmTickMarkers[iNextTickIndex].tm_slTickOffset); } return EMB_SUCCESS_OK; }; void CEMsgBuffer::WriteTick(float tm_fTickTime,const void *pv, SLONG slSize) { ASSERT(slSize>=0 && pv!=NULL); StartNewTick(tm_fTickTime); WriteBytes(pv,slSize); }; int CEMsgBuffer::MoveToStartOfTick(float fTickTime) { int iErr; INDEX iTickIndex; ASSERT(fTickTime >= emb_atmTickMarkers[emb_iFirstTickMarker].tm_fTickTime); iErr = GetTickIndex(fTickTime,iTickIndex); if (iErr != EMB_SUCCESS_OK) { return iErr; } // if not wrapping if (iTickIndex >= emb_iFirstTickMarker) { emb_uwNumTickMarkers -= iTickIndex - emb_iFirstTickMarker; } else { emb_uwNumTickMarkers -= iTickIndex + (MAX_TICKS_KEPT - emb_iFirstTickMarker); } emb_iFirstTickMarker = iTickIndex; if (bu_slReadOffset <= emb_atmTickMarkers[iTickIndex].tm_slTickOffset) { bu_slFree += emb_atmTickMarkers[iTickIndex].tm_slTickOffset - bu_slReadOffset; } else { bu_slFree += (bu_slSize - bu_slReadOffset) + emb_atmTickMarkers[iTickIndex].tm_slTickOffset; } bu_slReadOffset = emb_atmTickMarkers[iTickIndex].tm_slTickOffset; return EMB_SUCCESS_OK; }; // expand buffer to be given number of bytes in size void CEMsgBuffer::Expand(SLONG slNewSize) { ASSERT(slNewSize>0); ASSERT(bu_slSize>=0); // if not already allocated if (bu_slSize==0) { // allocate a new empty buffer ASSERT(bu_pubBuffer==NULL); bu_pubBuffer = (UBYTE*)AllocMemory(slNewSize); bu_slWriteOffset = 0; bu_slReadOffset = 0; bu_slFree = slNewSize; bu_slSize = slNewSize; // if already allocated } else { ASSERT(slNewSize>bu_slSize); SLONG slSizeDiff = slNewSize-bu_slSize; ASSERT(bu_pubBuffer!=NULL); // grow buffer GrowMemory((void**)&bu_pubBuffer, slNewSize); cout << "EXPAND!\n"; // if buffer is currently wrapping if (bu_slReadOffset>bu_slWriteOffset||bu_slFree==0) { cout << "WRAP!\n"; // move part at the end of buffer to the end memmove(bu_pubBuffer+bu_slReadOffset+slSizeDiff, bu_pubBuffer+bu_slReadOffset,bu_slSize-bu_slReadOffset); for (int i=0;i= bu_slReadOffset) { emb_atmTickMarkers[i].tm_slTickOffset += slSizeDiff; } } bu_slReadOffset+=slSizeDiff; } bu_slFree += slNewSize-bu_slSize; bu_slSize = slNewSize; ASSERT(bu_slReadOffset>=0 && bu_slReadOffset=0 && bu_slFree<=bu_slSize); } } // write bytes to buffer void CEMsgBuffer::WriteBytes(const void *pv, SLONG slSize) { BOOL bWraping = FALSE; SLONG slOldReadOffset = bu_slReadOffset; // if buffer is currently wrapping ASSERT(slSize>=0 && pv!=NULL); // if there is nothing to write if (slSize==0) { // do nothing return; } // check for errors if (slSize<0) { cout << "WARNING: WriteBytes(): slSize<0\n!"; return; } // if there is not enough free space if (bu_slFreebu_slWriteOffset||bu_slFree==0) { // bWraping = TRUE; // } // expand the buffer Expand(slNewSize); ASSERT(bu_slFree>=slSize); } UBYTE *pub = (UBYTE*)pv; // write part of block at the end of buffer SLONG slSizeEnd = __min(bu_slSize-bu_slWriteOffset, slSize); memcpy(bu_pubBuffer+bu_slWriteOffset, pub, slSizeEnd); pub+=slSizeEnd; memcpy(bu_pubBuffer, pub, slSize-slSizeEnd); // move write pointer bu_slWriteOffset+=slSize; bu_slWriteOffset%=bu_slSize; bu_slFree-=slSize; ASSERT(bu_slWriteOffset>=0 && bu_slWriteOffset=0 && bu_slFree<=bu_slSize); }; SLONG CEMsgBuffer::PeekBytes(const void *pv, SLONG slSize) { ASSERT(slSize>0 && pv!=NULL); UBYTE *pub = (UBYTE*)pv; // clamp size to amount of bytes actually in the buffer SLONG slUsed = bu_slSize-bu_slFree; if (slUsed=0 && bu_slReadOffset=0 && bu_slFree<=bu_slSize); return slSize; } SLONG CEMsgBuffer::PeekBytesAtOffset(const void *pv, SLONG slSize,SLONG &slTickOffset) { ASSERT(slSize>0 && pv!=NULL); UBYTE *pub = (UBYTE*)pv; // clamp size to amount of bytes actually in the buffer SLONG slUsed = bu_slSize-bu_slFree; if (slUsed=0 && slTickOffset=0 && bu_slFree<=bu_slSize); return slSize; }