258 lines
7.4 KiB
C++
258 lines
7.4 KiB
C++
#pragma once
|
|
|
|
#include "ISystem.h" // ISystem
|
|
#include "IGame.h" // IGame
|
|
#include "IStreamEngine.h" // IStreamEngine
|
|
|
|
#if defined(LINUX)
|
|
// #include "stream.h"
|
|
#endif
|
|
|
|
// usable:
|
|
//
|
|
// CStreamData_WorldPos Vec3(x,y,z) world position with fallback if outside of typical area
|
|
// CStreamData_Normal normalized Vec3(x,y,z) in very well compressed in 16bit (cubemap side+2d pos on cubemap)
|
|
|
|
// next possible candidates:
|
|
//
|
|
// Direction Vec3, components in range -1..1
|
|
// Angle range: 0..2*PI
|
|
// EulerAnglesXYZ components in range: 0..2*PI
|
|
// EulerAnglesXZ components in range: 0..2*PI
|
|
//
|
|
|
|
// todo:
|
|
//
|
|
// test the whole system in multiplayer
|
|
// save stream compression mask in file or init 0 for load and save
|
|
// check if fallback is working
|
|
|
|
// -------------------------------------------------------------------------------------------------------------
|
|
|
|
class CStreamDataBase :public IStreamData
|
|
{
|
|
public:
|
|
//!
|
|
static bool DoCompression( const DWORD indwMask )
|
|
{
|
|
ISystem *pSystem=GetISystem(); assert(pSystem);
|
|
IGame *pGame=pSystem->GetIGame(); assert(pGame);
|
|
IStreamEngine *pStreamE=pSystem->GetStreamEngine(); assert(pStreamE);
|
|
|
|
if(!pGame->GetModuleState(EGameMultiplayer))
|
|
return false; // compression is only needed to save bandwidth
|
|
|
|
return (pStreamE->GetStreamCompressionMask()&indwMask) !=0;
|
|
}
|
|
};
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------
|
|
// -------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
// world position (always positive) 96 -> 59 bits for 2mm resolution
|
|
class CStreamData_WorldPos :public CStreamDataBase
|
|
{
|
|
Vec3 & m_vData; //!< reference to the Vec3 data
|
|
|
|
public: // --------------------------
|
|
|
|
//! constructor
|
|
CStreamData_WorldPos( Vec3 &inoutvValue ) :m_vData(inoutvValue)
|
|
{
|
|
}
|
|
|
|
//! to reproduce the quality loss form compression and decompression
|
|
Vec3 GetCompressed() const
|
|
{
|
|
CStream stm;
|
|
|
|
Write(stm);Read(stm);
|
|
|
|
return m_vData;
|
|
}
|
|
|
|
static bool IsActive()
|
|
{
|
|
ISystem *pSystem=GetISystem(); assert(pSystem);
|
|
IGame *pGame=pSystem->GetIGame(); assert(pGame);
|
|
|
|
// return DoCompression(0x1);
|
|
return pGame->GetModuleState(EGameMultiplayer); // compression is only needed to save bandwidth
|
|
}
|
|
|
|
// interface IStreamData -----------------------------
|
|
|
|
virtual bool Read( CStream &inStream ) const
|
|
{
|
|
if(!IsActive()) // same mask for read and write
|
|
return inStream.Read(m_vData);
|
|
|
|
bool bCompressed;
|
|
|
|
if(!inStream.Read(bCompressed)) return false;
|
|
|
|
if(!bCompressed)
|
|
return inStream.Read(m_vData);
|
|
|
|
DWORD x=0,y=0,z=0;
|
|
|
|
if(!inStream.ReadNumberInBits((unsigned int&)x, (size_t)20)) return false;
|
|
if(!inStream.ReadNumberInBits((unsigned int&)y, (size_t)20)) return false;
|
|
if(!inStream.ReadNumberInBits((unsigned int&)z, (size_t)18)) return false;
|
|
|
|
m_vData=Vec3((float)x,(float)y,(float)z) * 0.002f; // 2mm units
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual bool Write( CStream &inStream ) const
|
|
{
|
|
if(!IsActive()) // same mask for read and write
|
|
return inStream.Write(m_vData);
|
|
|
|
DWORD x,y,z;
|
|
|
|
if(m_vData.x<0 || m_vData.x>2048.0f // do a fallback outside of the typical world area
|
|
|| m_vData.y<0 || m_vData.y>2048.0f
|
|
|| m_vData.z<0 || m_vData.z>512.0f)
|
|
{
|
|
if(!inStream.Write(false)) return false; // uncompressed
|
|
return inStream.Write(m_vData);
|
|
}
|
|
|
|
x=(DWORD)(m_vData.x*500.0f+0.5f); // 2mm units +0.5f for rounding
|
|
y=(DWORD)(m_vData.y*500.0f+0.5f);
|
|
z=(DWORD)(m_vData.z*500.0f+0.5f);
|
|
|
|
if(!inStream.Write(true)) return false; // compressed
|
|
|
|
if(!inStream.WriteNumberInBits((unsigned int)x, 20)) return false;
|
|
if(!inStream.WriteNumberInBits((unsigned int)y, 20)) return false;
|
|
if(!inStream.WriteNumberInBits((unsigned int)z, 18)) return false;
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------
|
|
// -------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
// low quality (16bit) normalized vector 96 -> 16 bits
|
|
// projected on a cube: x=0..104 x y=0..140 x side=0..5 -> 0.. 64896
|
|
class CStreamData_Normal :public CStreamDataBase
|
|
{
|
|
Vec3 & m_vData; //!< reference to the Vec3 data
|
|
|
|
public: // --------------------------
|
|
|
|
//! constructor
|
|
CStreamData_Normal( Vec3 &inoutvValue ) :m_vData(inoutvValue)
|
|
{
|
|
}
|
|
|
|
//! to reproduce the quality loss form compression and decompression
|
|
Vec3 GetCompressed() const
|
|
{
|
|
CStream stm;
|
|
|
|
Write(stm);Read(stm);
|
|
|
|
return m_vData;
|
|
}
|
|
|
|
static bool IsActive()
|
|
{
|
|
ISystem *pSystem=GetISystem(); assert(pSystem);
|
|
IGame *pGame = pSystem->GetIGame(); assert(pGame);
|
|
|
|
// return DoCompression(0x4);
|
|
return pGame->GetModuleState(EGameMultiplayer); // compression is only needed to save bandwidth
|
|
}
|
|
|
|
// interface IStreamData -----------------------------
|
|
|
|
virtual bool Read( CStream &inStream ) const
|
|
{
|
|
if(!IsActive()) // same mask for read and write
|
|
return inStream.Read(m_vData);
|
|
|
|
DWORD dwWord=0;
|
|
|
|
if(!inStream.ReadNumberInBits((unsigned int&)dwWord, (size_t)16)) return false;
|
|
|
|
DWORD dwDominantDirection=dwWord%6;
|
|
DWORD dwIntermediate=dwWord / 6; // 6 sides
|
|
DWORD dwX=dwIntermediate % 104; // 104 values on a cube size
|
|
DWORD dwY=dwIntermediate / 104; // 104 values on a cube size
|
|
|
|
float fX=(((float)dwX+0.5f)/(float)(104))*2.0f-1.0f;
|
|
float fY=(((float)dwY+0.5f)/(float)(104))*2.0f-1.0f;
|
|
|
|
switch(dwDominantDirection)
|
|
{
|
|
case 0: m_vData[0]=1.0f; m_vData[1]=fX; m_vData[2]=fY; break;
|
|
case 1: m_vData[0]=fY; m_vData[1]=1.0f; m_vData[2]=fX; break;
|
|
case 2: m_vData[0]=fX; m_vData[1]=fY; m_vData[2]=1.0f; break;
|
|
case 3: m_vData[0]=-1.0f; m_vData[1]=fX; m_vData[2]=fY; break;
|
|
case 4: m_vData[0]=fY; m_vData[1]=-1.0f; m_vData[2]=fX; break;
|
|
case 5: m_vData[0]=fX; m_vData[1]=fY; m_vData[2]=-1.0f; break;
|
|
default: assert(0);
|
|
}
|
|
|
|
m_vData.Normalize();
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual bool Write( CStream &inStream ) const
|
|
{
|
|
if(!IsActive()) // same mask for read and write
|
|
return inStream.Write(m_vData);
|
|
|
|
int iDominantDirection=-1;
|
|
|
|
float vAbs[3]={ m_vData[0], m_vData[1], m_vData[2] };
|
|
|
|
// calc absolute value
|
|
if(vAbs[0]<0)vAbs[0]=-vAbs[0];
|
|
if(vAbs[1]<0)vAbs[1]=-vAbs[1];
|
|
if(vAbs[2]<0)vAbs[2]=-vAbs[2];
|
|
|
|
if(vAbs[0]>=vAbs[1] && vAbs[0]>=vAbs[2])iDominantDirection=0;
|
|
else
|
|
if(vAbs[1]>=vAbs[0] && vAbs[1]>=vAbs[2])iDominantDirection=1;
|
|
else
|
|
if(vAbs[2]>=vAbs[1] && vAbs[2]>=vAbs[0])iDominantDirection=2;
|
|
|
|
assert(iDominantDirection!=-1 && "this should never hapen or the vector has zero length");
|
|
if(iDominantDirection==-1)iDominantDirection=0;
|
|
|
|
float fX=m_vData[(iDominantDirection+1)%3];
|
|
float fY=m_vData[(iDominantDirection+2)%3];
|
|
float fZ=m_vData[iDominantDirection];
|
|
|
|
if(vAbs[iDominantDirection]!=m_vData[iDominantDirection])iDominantDirection+=3;
|
|
|
|
float fScale=1.0f/(float)fabs(fZ);
|
|
|
|
fX*=fScale;fY*=fScale;
|
|
|
|
DWORD dwX=(DWORD)((fX*0.5f+0.5f)*104); // 104 values on a cube size
|
|
DWORD dwY=(DWORD)((fY*0.5f+0.5f)*104); // 104 values on a cube size
|
|
|
|
if(dwX>=104)dwX=104-1; // 104 values on a cube size
|
|
if(dwY>=104)dwY=104-1; // 104 values on a cube size
|
|
|
|
DWORD dwWord=iDominantDirection+6*(dwX+104*dwY); // 104 values on a cube size
|
|
|
|
if(!inStream.WriteNumberInBits((unsigned int)dwWord, 16)) return false;
|
|
|
|
return true;
|
|
}
|
|
};
|