Serious-Engine/Sources/Engine/Network/EMsgBuffer.cpp
2016-03-11 18:20:51 -06:00

836 lines
22 KiB
C++

/* 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 <Engine/Math/Functions.h>
#include <Engine/Base/Memory.h>
#include <Engine/Math/Quaternion.h>
void AngleToUL(ANGLE3D &Angle,ULONG &ulResult)
{
Quaternion<float> 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) (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<float> qQuat;
FLOAT3D Axis;
float fRotAngle;
ANGLE3D AxisAngles;
UBYTE ubDir;
UWORD swAngle;
Matrix<float,3,3> 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<MAX_TICKS_KEPT;i++) {
emb_atmTickMarkers[i].tm_slTickOffset = -1;
emb_atmTickMarkers[i].tm_fTickTime = -1;
emb_atmTickMarkers[i].tm_ubAcknowledgesExpected = 0;
}
};
CEMsgBuffer::~CEMsgBuffer ()
{
};
void CEMsgBuffer::Clear(void)
{
emb_uwNumTickMarkers = 0;
emb_iFirstTickMarker = 0;
emb_iCurrentTickMarker = 0;
emb_fCurrentTickTime = -1;
for (int i=0;i<MAX_TICKS_KEPT;i++) {
emb_atmTickMarkers[i].tm_slTickOffset = -1;
emb_atmTickMarkers[i].tm_fTickTime = -1;
emb_atmTickMarkers[i].tm_ubAcknowledgesExpected = 0;
}
bu_slWriteOffset = 0;
bu_slReadOffset = 0;
bu_slFree = bu_slSize;
};
void CEMsgBuffer::WriteMessage(CEntityMessage &emEntityMessage)
{
// a tick must have started before any messages are generated
ASSERT (emb_uwNumTickMarkers > 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;i<emb_uwNumTickMarkers;i++) {
iTickMarker = (i + emb_iFirstTickMarker) % MAX_TICKS_KEPT;
if (fabs(emb_atmTickMarkers[iTickMarker].tm_fTickTime - fTickTime) < 0.025) {
iTickIndex = iTickMarker;
return EMB_SUCCESS_OK;
}
}
iTickIndex = -1;
return EMB_ERR_NOT_IN_BUFFER;
};
int CEMsgBuffer::GetTickOffset(float fTickTime,SLONG &slTickOffset)
{
INDEX iTickMarker;
// 0.025 should be _pTimer->TickQuantum/2
for (int i=0;i<emb_uwNumTickMarkers;i++) {
iTickMarker = (i + emb_iFirstTickMarker) % MAX_TICKS_KEPT;
if (fabs(emb_atmTickMarkers[iTickMarker].tm_fTickTime - fTickTime) < 0.025) {
slTickOffset = emb_atmTickMarkers[iTickMarker].tm_slTickOffset;
return EMB_SUCCESS_OK;
}
}
slTickOffset = -1.0f;
return EMB_ERR_NOT_IN_BUFFER;
};
int CEMsgBuffer::GetNextTickTime(float fTickTime,float &fNextTickTime)
{
INDEX iTickIndex;
int iErr;
if (fTickTime < 0) {
if (emb_uwNumTickMarkers > 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<MAX_TICKS_KEPT;i++) {
if (emb_atmTickMarkers[i].tm_slTickOffset >= 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<bu_slSize);
ASSERT(bu_slFree>=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_slFree<slSize) {
SLONG slSizeDiff;
SLONG slNewSize;
slNewSize = bu_slSize + ((slSize-bu_slFree + bu_slAllocationStep - 1) / bu_slAllocationStep) * bu_slAllocationStep;
slSizeDiff = slNewSize - bu_slSize;
// if buffer is currently wrapping
// if (bu_slReadOffset>bu_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<bu_slSize);
ASSERT(bu_slFree>=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<slSize) {
slSize = slUsed;
}
// if there is nothing to read
if (slSize==0) {
// do nothing
return 0;
}
// read part of block after read pointer to the end of buffer
SLONG slSizeEnd = __min(bu_slSize-bu_slReadOffset, slSize);
memcpy(pub, bu_pubBuffer+bu_slReadOffset, slSizeEnd);
pub+=slSizeEnd;
// if that is not all
if (slSizeEnd<slSize) {
// read rest from start of buffer
memcpy(pub, bu_pubBuffer, slSize-slSizeEnd);
}
ASSERT(bu_slReadOffset>=0 && bu_slReadOffset<bu_slSize);
ASSERT(bu_slFree>=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<slSize) {
slSize = slUsed;
}
// if there is nothing to read
if (slSize==0) {
// do nothing
return 0;
}
// read part of block after read pointer to the end of buffer
SLONG slSizeEnd = __min(bu_slSize-slTickOffset, slSize);
memcpy(pub, bu_pubBuffer+slTickOffset, slSizeEnd);
pub+=slSizeEnd;
slTickOffset += slSizeEnd;
// if that is not all
if (slSizeEnd<slSize) {
// read rest from start of buffer
memcpy(pub, bu_pubBuffer, slSize-slSizeEnd);
slTickOffset = slSize - slSizeEnd;
}
slTickOffset %= bu_slSize;
ASSERT(slTickOffset>=0 && slTickOffset<bu_slSize);
ASSERT(bu_slFree>=0 && bu_slFree<=bu_slSize);
return slSize;
}