Non-initial commit

This commit is contained in:
Jordan Cristiano 2014-10-29 00:20:24 -04:00
parent 347f2c439c
commit 65810867d8
9 changed files with 1429 additions and 0 deletions

3
.gitignore vendored
View File

@ -26,3 +26,6 @@
*.exe *.exe
*.out *.out
*.app *.app
# Generated Project Files
premake/*/

20
demboyz/demboyz.cpp Normal file
View File

@ -0,0 +1,20 @@
#include "demofile.h"
int main(const int argc, const char* argv[])
{
if (argc < 2)
{
return -1;
}
CDemoFile demoFile;
if (!demoFile.Open(argv[1]))
{
return -1;
}
demoFile.Close();
return 0;
}

192
demboyz/demofile.cpp Normal file
View File

@ -0,0 +1,192 @@
//====== Copyright (c) 2014, Valve Corporation, All rights reserved. ========//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//===========================================================================//
#include <stdio.h>
#include <cstring>
#include <assert.h>
#include "demofile.h"
CDemoFile::CDemoFile()
{
}
CDemoFile::~CDemoFile()
{
Close();
}
void CDemoFile::ReadSequenceInfo( int32 &nSeqNrIn, int32 &nSeqNrOut )
{
if ( !m_fileBuffer.size() )
return;
nSeqNrIn = *( int32 * )( &m_fileBuffer[ m_fileBufferPos ] );
m_fileBufferPos += sizeof( int32 );
nSeqNrOut = *( int32 * )( &m_fileBuffer[ m_fileBufferPos ] );
m_fileBufferPos += sizeof( int32 );
}
void CDemoFile::ReadCmdInfo( democmdinfo_t& info )
{
if ( !m_fileBuffer.size() )
return;
memcpy( &info, &m_fileBuffer[ m_fileBufferPos ], sizeof( democmdinfo_t ) );
m_fileBufferPos += sizeof( democmdinfo_t );
}
void CDemoFile::ReadCmdHeader( unsigned char& cmd, int32& tick, unsigned char& playerSlot )
{
if ( !m_fileBuffer.size() )
return;
// Read the command
cmd = *( unsigned char * )( &m_fileBuffer[ m_fileBufferPos ] );
m_fileBufferPos += sizeof( unsigned char );
if ( cmd <=0 )
{
fprintf( stderr, "CDemoFile::ReadCmdHeader: Missing end tag in demo file.\n");
cmd = dem_stop;
return;
}
assert( cmd >= 1 && cmd <= dem_lastcmd );
// Read the timestamp
tick = *( int32 * )( &m_fileBuffer[ m_fileBufferPos ] );
m_fileBufferPos += sizeof( int32 );
// read playerslot
playerSlot = *( unsigned char * )( &m_fileBuffer[ m_fileBufferPos ] );
m_fileBufferPos += sizeof( unsigned char );
}
int32 CDemoFile::ReadUserCmd( char *buffer, int32 &size )
{
if ( !m_fileBuffer.size() )
return 0;
int32 outgoing_sequence = *( int32 * )( &m_fileBuffer[ m_fileBufferPos ] );
m_fileBufferPos += sizeof( int32 );
size = ReadRawData( buffer, size );
return outgoing_sequence;
}
int32 CDemoFile::ReadRawData( char *buffer, int32 length )
{
if ( !m_fileBuffer.size() )
return 0;
// read length of data block
int32 size = *( int32 * )( &m_fileBuffer[ m_fileBufferPos ] );
m_fileBufferPos += sizeof( int32 );
if ( buffer && (length < size) )
{
fprintf( stderr, "CDemoFile::ReadRawData: buffer overflow (%i).\n", size );
return -1;
}
if ( buffer )
{
// read data into buffer
memcpy( buffer, &m_fileBuffer[ m_fileBufferPos ], size );
m_fileBufferPos += size;
}
else
{
// just skip it
m_fileBufferPos += size;
}
return size;
}
bool CDemoFile::Open( const char *name )
{
Close();
FILE *fp = NULL;
fp = fopen( name, "rb" );
if( fp )
{
size_t Length;
fseek( fp, 0, SEEK_END );
Length = ftell( fp );
fseek( fp, 0, SEEK_SET );
if( Length < sizeof( m_DemoHeader ) )
{
fprintf( stderr, "CDemoFile::Open: file too small. %s.\n", name );
fclose( fp );
return false;
}
fread( &m_DemoHeader, 1, sizeof( m_DemoHeader ), fp );
Length -= sizeof( m_DemoHeader );
if ( strcmp ( m_DemoHeader.demofilestamp, DEMO_HEADER_ID ) )
{
fprintf( stderr, "CDemoFile::Open: %s has invalid demo header ID.\n", m_szFileName.c_str() );
fclose( fp );
return false;
}
if ( m_DemoHeader.demoprotocol != DEMO_PROTOCOL )
{
fprintf( stderr, "CDemoFile::Open: demo file protocol %i invalid, expected version is %i \n", m_DemoHeader.demoprotocol, DEMO_PROTOCOL );
fclose( fp );
return false;
}
m_fileBuffer.resize( Length );
fread( &m_fileBuffer[ 0 ], 1, Length, fp );
fclose( fp );
fp = NULL;
}
if ( !m_fileBuffer.size() )
{
fprintf( stderr, "CDemoFile::Open: couldn't open file %s.\n", name );
Close();
return false;
}
m_fileBufferPos = 0;
m_szFileName = name;
return true;
}
void CDemoFile::Close()
{
m_szFileName.clear();
m_fileBufferPos = 0;
m_fileBuffer.clear();
}

251
demboyz/demofile.h Normal file
View File

@ -0,0 +1,251 @@
//====== Copyright (c) 2014, Valve Corporation, All rights reserved. ========//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//===========================================================================//
#ifndef DEMOFILE_H
#define DEMOFILE_H
#ifdef _WIN32
#pragma once
#endif
#include <string>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#define DEMO_HEADER_ID "HL2DEMO"
#define DEMO_PROTOCOL 4
#if !defined( MAX_OSPATH )
#define MAX_OSPATH 260 // max length of a filesystem pathname
#endif
typedef int32_t int32;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
typedef unsigned long CRC32_t;
// Demo messages
enum
{
// it's a startup message, process as fast as possible
dem_signon = 1,
// it's a normal network packet that we stored off
dem_packet,
// sync client clock to demo tick
dem_synctick,
// console command
dem_consolecmd,
// user input command
dem_usercmd,
// network data tables
dem_datatables,
// end of time.
dem_stop,
// a blob of binary data understood by a callback function
dem_customdata,
dem_stringtables,
// Last command
dem_lastcmd = dem_stringtables
};
struct demoheader_t
{
char demofilestamp[ 8 ]; // Should be HL2DEMO
int32 demoprotocol; // Should be DEMO_PROTOCOL
int32 networkprotocol; // Should be PROTOCOL_VERSION
char servername[ MAX_OSPATH ]; // Name of server
char clientname[ MAX_OSPATH ]; // Name of client who recorded the game
char mapname[ MAX_OSPATH ]; // Name of map
char gamedirectory[ MAX_OSPATH ]; // Name of game directory (com_gamedir)
float playback_time; // Time of track
int32 playback_ticks; // # of ticks in track
int32 playback_frames; // # of frames in track
int32 signonlength; // length of sigondata in bytes
};
#define FDEMO_NORMAL 0
#define FDEMO_USE_ORIGIN2 ( 1 << 0 )
#define FDEMO_USE_ANGLES2 ( 1 << 1 )
#define FDEMO_NOINTERP ( 1 << 2 ) // don't interpolate between this an last view
#define MAX_SPLITSCREEN_CLIENTS 2
struct QAngle
{
float x, y, z;
void Init( void )
{
x = y = z = 0.0f;
}
void Init( float _x, float _y, float _z )
{
x = _x;
y = _y;
z = _z;
}
};
struct Vector
{
float x, y, z;
void Init( void )
{
x = y = z = 0.0f;
}
void Init( float _x, float _y, float _z )
{
x = _x;
y = _y;
z = _z;
}
};
struct democmdinfo_t
{
democmdinfo_t( void )
{
}
struct Split_t
{
Split_t( void )
{
flags = FDEMO_NORMAL;
viewOrigin.Init();
viewAngles.Init();
localViewAngles.Init();
// Resampled origin/angles
viewOrigin2.Init();
viewAngles2.Init();
localViewAngles2.Init();
}
Split_t& operator=( const Split_t& src )
{
if ( this == &src )
return *this;
flags = src.flags;
viewOrigin = src.viewOrigin;
viewAngles = src.viewAngles;
localViewAngles = src.localViewAngles;
viewOrigin2 = src.viewOrigin2;
viewAngles2 = src.viewAngles2;
localViewAngles2 = src.localViewAngles2;
return *this;
}
const Vector& GetViewOrigin( void )
{
if ( flags & FDEMO_USE_ORIGIN2 )
{
return viewOrigin2;
}
return viewOrigin;
}
const QAngle& GetViewAngles( void )
{
if ( flags & FDEMO_USE_ANGLES2 )
{
return viewAngles2;
}
return viewAngles;
}
const QAngle& GetLocalViewAngles( void )
{
if ( flags & FDEMO_USE_ANGLES2 )
{
return localViewAngles2;
}
return localViewAngles;
}
void Reset( void )
{
flags = 0;
viewOrigin2 = viewOrigin;
viewAngles2 = viewAngles;
localViewAngles2 = localViewAngles;
}
int32 flags;
// original origin/viewangles
Vector viewOrigin;
QAngle viewAngles;
QAngle localViewAngles;
// Resampled origin/viewangles
Vector viewOrigin2;
QAngle viewAngles2;
QAngle localViewAngles2;
};
void Reset( void )
{
for ( int i = 0; i < MAX_SPLITSCREEN_CLIENTS; ++i )
{
u[ i ].Reset();
}
}
Split_t u[ MAX_SPLITSCREEN_CLIENTS ];
};
class CDemoFile
{
public:
CDemoFile();
virtual ~CDemoFile();
bool Open( const char *name );
void Close();
int32 ReadRawData( char *buffer, int32 length );
void ReadSequenceInfo( int32 &nSeqNrIn, int32 &nSeqNrOutAck );
void ReadCmdInfo( democmdinfo_t& info );
void ReadCmdHeader( unsigned char &cmd, int32 &tick, unsigned char& playerSlot );
int32 ReadUserCmd( char *buffer, int32 &size );
demoheader_t *ReadDemoHeader();
public:
demoheader_t m_DemoHeader; //general demo info
std::string m_szFileName;
size_t m_fileBufferPos;
std::string m_fileBuffer;
};
#endif // DEMOFILE_H

691
demboyz/demofilebitbuf.cpp Normal file
View File

@ -0,0 +1,691 @@
//====== Copyright (c) 2014, Valve Corporation, All rights reserved. ========//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//===========================================================================//
#include <assert.h>
#include "demofilebitbuf.h"
const uint32 CBitRead::s_nMaskTable[33] = {
0,
( 1 << 1 ) - 1,
( 1 << 2 ) - 1,
( 1 << 3 ) - 1,
( 1 << 4 ) - 1,
( 1 << 5 ) - 1,
( 1 << 6 ) - 1,
( 1 << 7 ) - 1,
( 1 << 8 ) - 1,
( 1 << 9 ) - 1,
( 1 << 10 ) - 1,
( 1 << 11 ) - 1,
( 1 << 12 ) - 1,
( 1 << 13 ) - 1,
( 1 << 14 ) - 1,
( 1 << 15 ) - 1,
( 1 << 16 ) - 1,
( 1 << 17 ) - 1,
( 1 << 18 ) - 1,
( 1 << 19 ) - 1,
( 1 << 20 ) - 1,
( 1 << 21 ) - 1,
( 1 << 22 ) - 1,
( 1 << 23 ) - 1,
( 1 << 24 ) - 1,
( 1 << 25 ) - 1,
( 1 << 26 ) - 1,
( 1 << 27 ) - 1,
( 1 << 28 ) - 1,
( 1 << 29 ) - 1,
( 1 << 30 ) - 1,
0x7fffffff,
0xffffffff,
};
int CBitRead::GetNumBitsRead( void ) const
{
if ( ! m_pData ) // pesky null ptr bitbufs. these happen.
return 0;
int nCurOfs = ( ( int( m_pDataIn ) - int( m_pData ) ) / 4 ) - 1;
nCurOfs *= 32;
nCurOfs += ( 32 - m_nBitsAvail );
int nAdjust = 8 * ( m_nDataBytes & 3 );
return MIN( nCurOfs + nAdjust, m_nDataBits );
}
int CBitRead::GetNumBytesRead( void ) const
{
return ( ( GetNumBitsRead() + 7 ) >> 3 );
}
void CBitRead::GrabNextDWord( bool bOverFlowImmediately )
{
if ( m_pDataIn == m_pBufferEnd )
{
m_nBitsAvail = 1; // so that next read will run out of words
m_nInBufWord = 0;
m_pDataIn++; // so seek count increments like old
if ( bOverFlowImmediately )
{
SetOverflowFlag();
}
}
else
if ( m_pDataIn > m_pBufferEnd )
{
SetOverflowFlag();
m_nInBufWord = 0;
}
else
{
assert( reinterpret_cast< int >( m_pDataIn ) + 3 < reinterpret_cast< int >( m_pBufferEnd ) );
m_nInBufWord = *( m_pDataIn++ );
}
}
void CBitRead::FetchNext( void )
{
m_nBitsAvail = 32;
GrabNextDWord( false );
}
int CBitRead::ReadOneBit( void )
{
int nRet = m_nInBufWord & 1;
if ( --m_nBitsAvail == 0 )
{
FetchNext();
}
else
{
m_nInBufWord >>= 1;
}
return nRet;
}
unsigned int CBitRead::ReadUBitLong( int numbits )
{
if ( m_nBitsAvail >= numbits )
{
unsigned int nRet = m_nInBufWord & s_nMaskTable[ numbits ];
m_nBitsAvail -= numbits;
if ( m_nBitsAvail )
{
m_nInBufWord >>= numbits;
}
else
{
FetchNext();
}
return nRet;
}
else
{
// need to merge words
unsigned int nRet = m_nInBufWord;
numbits -= m_nBitsAvail;
GrabNextDWord( true );
if ( m_bOverflow )
return 0;
nRet |= ( ( m_nInBufWord & s_nMaskTable[ numbits ] ) << m_nBitsAvail );
m_nBitsAvail = 32 - numbits;
m_nInBufWord >>= numbits;
return nRet;
}
}
int CBitRead::ReadSBitLong( int numbits )
{
int nRet = ReadUBitLong( numbits );
// sign extend
return ( nRet << ( 32 - numbits ) ) >> ( 32 - numbits );
}
#ifdef _WIN32
#pragma warning(push)
#pragma warning(disable : 4715) // disable warning on not all cases
// returning a value. throwing default:
// in measurably reduces perf in bit
// packing benchmark
#endif
unsigned int CBitRead::ReadUBitVar( void )
{
unsigned int ret = ReadUBitLong( 6 );
switch( ret & ( 16 | 32 ) )
{
case 16:
ret = ( ret & 15 ) | ( ReadUBitLong( 4 ) << 4 );
assert( ret >= 16);
break;
case 32:
ret = ( ret & 15 ) | ( ReadUBitLong( 8 ) << 4 );
assert( ret >= 256);
break;
case 48:
ret = ( ret & 15 ) | ( ReadUBitLong( 32 - 4 ) << 4 );
assert( ret >= 4096 );
break;
}
return ret;
}
#ifdef _WIN32
#pragma warning(pop)
#endif
int CBitRead::ReadChar( void )
{
return ReadSBitLong( sizeof( char ) << 3 );
}
int CBitRead::ReadByte( void )
{
return ReadUBitLong( sizeof( unsigned char ) << 3 );
}
int CBitRead::ReadShort( void )
{
return ReadSBitLong( sizeof( short ) << 3 );
}
int CBitRead::ReadWord( void )
{
return ReadUBitLong( sizeof( unsigned short ) << 3 );
}
bool CBitRead::Seek( int nPosition )
{
bool bSucc = true;
if ( nPosition < 0 || nPosition > m_nDataBits )
{
SetOverflowFlag();
bSucc = false;
nPosition = m_nDataBits;
}
int nHead = m_nDataBytes & 3; // non-multiple-of-4 bytes at head of buffer. We put the "round off"
// at the head to make reading and detecting the end efficient.
int nByteOfs = nPosition / 8;
if ( ( m_nDataBytes < 4 ) || ( nHead && ( nByteOfs < nHead ) ) )
{
// partial first dword
unsigned char const *pPartial = ( unsigned char const *) m_pData;
if ( m_pData )
{
m_nInBufWord = *( pPartial++ );
if ( nHead > 1 )
{
m_nInBufWord |= ( *pPartial++ ) << 8;
}
if ( nHead > 2 )
{
m_nInBufWord |= ( *pPartial++ ) << 16;
}
}
m_pDataIn = ( uint32 const * ) pPartial;
m_nInBufWord >>= ( nPosition & 31 );
m_nBitsAvail = ( nHead << 3 ) - ( nPosition & 31 );
}
else
{
int nAdjPosition = nPosition - ( nHead << 3 );
m_pDataIn = reinterpret_cast< uint32 const * > ( reinterpret_cast< unsigned char const * >( m_pData ) + ( ( nAdjPosition / 32 ) << 2 ) + nHead );
if ( m_pData )
{
m_nBitsAvail = 32;
GrabNextDWord();
}
else
{
m_nInBufWord = 0;
m_nBitsAvail = 1;
}
m_nInBufWord >>= ( nAdjPosition & 31 );
m_nBitsAvail = MIN( m_nBitsAvail, 32 - ( nAdjPosition & 31 ) ); // in case grabnextdword overflowed
}
return bSucc;
}
void CBitRead::StartReading( const void *pData, int nBytes, int iStartBit, int nBits )
{
// Make sure it's dword aligned and padded.
assert( ( ( unsigned long )pData & 3 ) == 0 );
m_pData = ( uint32 * ) pData;
m_pDataIn = m_pData;
m_nDataBytes = nBytes;
if ( nBits == -1 )
{
m_nDataBits = nBytes << 3;
}
else
{
assert( nBits <= nBytes * 8 );
m_nDataBits = nBits;
}
m_bOverflow = false;
m_pBufferEnd = reinterpret_cast< uint32 const * > ( reinterpret_cast< unsigned char const * >( m_pData ) + nBytes );
if ( m_pData )
{
Seek( iStartBit );
}
}
bool CBitRead::ReadString( char *pStr, int maxLen, bool bLine, int *pOutNumChars )
{
assert( maxLen != 0 );
bool bTooSmall = false;
int iChar = 0;
while(1)
{
char val = ReadChar();
if ( val == 0 )
break;
else if ( bLine && val == '\n' )
break;
if ( iChar < ( maxLen - 1 ) )
{
pStr[ iChar ] = val;
++iChar;
}
else
{
bTooSmall = true;
}
}
// Make sure it's null-terminated.
assert( iChar < maxLen );
pStr[ iChar ] = 0;
if ( pOutNumChars )
{
*pOutNumChars = iChar;
}
return !IsOverflowed() && !bTooSmall;
}
// Read 1-5 bytes in order to extract a 32-bit unsigned value from the
// stream. 7 data bits are extracted from each byte with the 8th bit used
// to indicate whether the loop should continue.
// This allows variable size numbers to be stored with tolerable
// efficiency. Numbers sizes that can be stored for various numbers of
// encoded bits are:
// 8-bits: 0-127
// 16-bits: 128-16383
// 24-bits: 16384-2097151
// 32-bits: 2097152-268435455
// 40-bits: 268435456-0xFFFFFFFF
uint32 CBitRead::ReadVarInt32()
{
uint32 result = 0;
int count = 0;
uint32 b;
do
{
if ( count == bitbuf::kMaxVarint32Bytes )
{
return result;
}
b = ReadUBitLong( 8 );
result |= ( b & 0x7F ) << ( 7 * count );
++count;
} while ( b & 0x80 );
return result;
}
uint64 CBitRead::ReadVarInt64()
{
uint64 result = 0;
int count = 0;
uint64 b;
do
{
if ( count == bitbuf::kMaxVarintBytes )
{
return result;
}
b = ReadUBitLong( 8 );
result |= static_cast<uint64>(b & 0x7F) << (7 * count);
++count;
} while (b & 0x80);
return result;
}
void CBitRead::ReadBits( void *pOutData, int nBits )
{
unsigned char *pOut = ( unsigned char* )pOutData;
int nBitsLeft = nBits;
// align output to dword boundary
while( ( ( unsigned long )pOut & 3 ) != 0 && nBitsLeft >= 8 )
{
*pOut = ( unsigned char )ReadUBitLong( 8 );
++pOut;
nBitsLeft -= 8;
}
// read dwords
while ( nBitsLeft >= 32 )
{
*( ( unsigned long* )pOut ) = ReadUBitLong( 32 );
pOut += sizeof( unsigned long );
nBitsLeft -= 32;
}
// read remaining bytes
while ( nBitsLeft >= 8 )
{
*pOut = ReadUBitLong( 8 );
++pOut;
nBitsLeft -= 8;
}
// read remaining bits
if ( nBitsLeft )
{
*pOut = ReadUBitLong( nBitsLeft );
}
}
bool CBitRead::ReadBytes( void *pOut, int nBytes )
{
ReadBits( pOut, nBytes << 3 );
return !IsOverflowed();
}
#define BITS_PER_INT 32
inline int GetBitForBitnum( int bitNum )
{
static int bitsForBitnum[] =
{
( 1 << 0 ),
( 1 << 1 ),
( 1 << 2 ),
( 1 << 3 ),
( 1 << 4 ),
( 1 << 5 ),
( 1 << 6 ),
( 1 << 7 ),
( 1 << 8 ),
( 1 << 9 ),
( 1 << 10 ),
( 1 << 11 ),
( 1 << 12 ),
( 1 << 13 ),
( 1 << 14 ),
( 1 << 15 ),
( 1 << 16 ),
( 1 << 17 ),
( 1 << 18 ),
( 1 << 19 ),
( 1 << 20 ),
( 1 << 21 ),
( 1 << 22 ),
( 1 << 23 ),
( 1 << 24 ),
( 1 << 25 ),
( 1 << 26 ),
( 1 << 27 ),
( 1 << 28 ),
( 1 << 29 ),
( 1 << 30 ),
( 1 << 31 ),
};
return bitsForBitnum[ (bitNum) & (BITS_PER_INT-1) ];
}
float CBitRead::ReadBitAngle( int numbits )
{
float shift = (float)( GetBitForBitnum(numbits) );
int i = ReadUBitLong( numbits );
float fReturn = (float)i * (360.0f / shift);
return fReturn;
}
// Basic Coordinate Routines (these contain bit-field size AND fixed point scaling constants)
float CBitRead::ReadBitCoord (void)
{
int intval=0,fractval=0,signbit=0;
float value = 0.0;
// Read the required integer and fraction flags
intval = ReadOneBit();
fractval = ReadOneBit();
// If we got either parse them, otherwise it's a zero.
if ( intval || fractval )
{
// Read the sign bit
signbit = ReadOneBit();
// If there's an integer, read it in
if ( intval )
{
// Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1;
}
// If there's a fraction, read it in
if ( fractval )
{
fractval = ReadUBitLong( COORD_FRACTIONAL_BITS );
}
// Calculate the correct floating point value
value = intval + ((float)fractval * COORD_RESOLUTION);
// Fixup the sign if negative.
if ( signbit )
value = -value;
}
return value;
}
float CBitRead::ReadBitCoordMP( EBitCoordType coordType )
{
bool bIntegral = ( coordType == kCW_Integral );
bool bLowPrecision = ( coordType == kCW_LowPrecision );
int intval=0,fractval=0,signbit=0;
float value = 0.0;
bool bInBounds = ReadOneBit() ? true : false;
if ( bIntegral )
{
// Read the required integer and fraction flags
intval = ReadOneBit();
// If we got either parse them, otherwise it's a zero.
if ( intval )
{
// Read the sign bit
signbit = ReadOneBit();
// If there's an integer, read it in
// Adjust the integers from [0..MAX_COORD_VALUE-1] to [1..MAX_COORD_VALUE]
if ( bInBounds )
{
value = ( float )( ReadUBitLong( COORD_INTEGER_BITS_MP ) + 1 );
}
else
{
value = ( float )( ReadUBitLong( COORD_INTEGER_BITS ) + 1 );
}
}
}
else
{
// Read the required integer and fraction flags
intval = ReadOneBit();
// Read the sign bit
signbit = ReadOneBit();
// If we got either parse them, otherwise it's a zero.
if ( intval )
{
if ( bInBounds )
{
intval = ReadUBitLong( COORD_INTEGER_BITS_MP ) + 1;
}
else
{
intval = ReadUBitLong( COORD_INTEGER_BITS ) + 1;
}
}
// If there's a fraction, read it in
fractval = ReadUBitLong( bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS );
// Calculate the correct floating point value
value = intval + ((float)fractval * ( bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION ) );
}
// Fixup the sign if negative.
if ( signbit )
value = -value;
return value;
}
float CBitRead::ReadBitCellCoord( int bits, EBitCoordType coordType )
{
bool bIntegral = ( coordType == kCW_Integral );
bool bLowPrecision = ( coordType == kCW_LowPrecision );
int intval=0,fractval=0;
float value = 0.0;
if ( bIntegral )
{
value = ( float )( ReadUBitLong( bits ) );
}
else
{
intval = ReadUBitLong( bits );
// If there's a fraction, read it in
fractval = ReadUBitLong( bLowPrecision ? COORD_FRACTIONAL_BITS_MP_LOWPRECISION : COORD_FRACTIONAL_BITS );
// Calculate the correct floating point value
value = intval + ((float)fractval * ( bLowPrecision ? COORD_RESOLUTION_LOWPRECISION : COORD_RESOLUTION ) );
}
return value;
}
void CBitRead::ReadBitVec3Coord( Vector& fa )
{
int xflag, yflag, zflag;
// This vector must be initialized! Otherwise, If any of the flags aren't set,
// the corresponding component will not be read and will be stack garbage.
fa.Init( 0, 0, 0 );
xflag = ReadOneBit();
yflag = ReadOneBit();
zflag = ReadOneBit();
if ( xflag )
fa.x = ReadBitCoord();
if ( yflag )
fa.y = ReadBitCoord();
if ( zflag )
fa.z = ReadBitCoord();
}
float CBitRead::ReadBitNormal (void)
{
// Read the sign bit
int signbit = ReadOneBit();
// Read the fractional part
unsigned int fractval = ReadUBitLong( NORMAL_FRACTIONAL_BITS );
// Calculate the correct floating point value
float value = (float)fractval * NORMAL_RESOLUTION;
// Fixup the sign if negative.
if ( signbit )
value = -value;
return value;
}
void CBitRead::ReadBitVec3Normal( Vector& fa )
{
int xflag = ReadOneBit();
int yflag = ReadOneBit();
if (xflag)
fa.x = ReadBitNormal();
else
fa.x = 0.0f;
if (yflag)
fa.y = ReadBitNormal();
else
fa.y = 0.0f;
// The first two imply the third (but not its sign)
int znegative = ReadOneBit();
float fafafbfb = fa.x * fa.x + fa.y * fa.y;
if (fafafbfb < 1.0f)
fa.z = sqrt( 1.0f - fafafbfb );
else
fa.z = 0.0f;
if (znegative)
fa.z = -fa.z;
}
void CBitRead::ReadBitAngles( QAngle& fa )
{
Vector tmp;
ReadBitVec3Coord( tmp );
fa.Init( tmp.x, tmp.y, tmp.z );
}
float CBitRead::ReadBitFloat( void )
{
uint32 nvalue = ReadUBitLong( 32 );
return *( ( float * ) &nvalue );
}

240
demboyz/demofilebitbuf.h Normal file
View File

@ -0,0 +1,240 @@
//====== Copyright (c) 2014, Valve Corporation, All rights reserved. ========//
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
//===========================================================================//
#ifndef DEMOFILEBITBUF_H
#define DEMOFILEBITBUF_H
#include <math.h>
#include "demofile.h"
// OVERALL Coordinate Size Limits used in COMMON.C MSG_*BitCoord() Routines (and someday the HUD)
#define COORD_INTEGER_BITS 14
#define COORD_FRACTIONAL_BITS 5
#define COORD_DENOMINATOR (1<<(COORD_FRACTIONAL_BITS))
#define COORD_RESOLUTION (1.0f/(COORD_DENOMINATOR))
// Special threshold for networking multiplayer origins
#define COORD_INTEGER_BITS_MP 11
#define COORD_FRACTIONAL_BITS_MP_LOWPRECISION 3
#define COORD_DENOMINATOR_LOWPRECISION (1<<(COORD_FRACTIONAL_BITS_MP_LOWPRECISION))
#define COORD_RESOLUTION_LOWPRECISION (1.0f/(COORD_DENOMINATOR_LOWPRECISION))
#define NORMAL_FRACTIONAL_BITS 11
#define NORMAL_DENOMINATOR ( (1<<(NORMAL_FRACTIONAL_BITS)) - 1 )
#define NORMAL_RESOLUTION (1.0f/(NORMAL_DENOMINATOR))
enum EBitCoordType
{
kCW_None,
kCW_LowPrecision,
kCW_Integral
};
//-----------------------------------------------------------------------------
// namespaced helpers
//-----------------------------------------------------------------------------
namespace bitbuf
{
// ZigZag Transform: Encodes signed integers so that they can be
// effectively used with varint encoding.
//
// varint operates on unsigned integers, encoding smaller numbers into
// fewer bytes. If you try to use it on a signed integer, it will treat
// this number as a very large unsigned integer, which means that even
// small signed numbers like -1 will take the maximum number of bytes
// (10) to encode. ZigZagEncode() maps signed integers to unsigned
// in such a way that those with a small absolute value will have smaller
// encoded values, making them appropriate for encoding using varint.
//
// int32 -> uint32
// -------------------------
// 0 -> 0
// -1 -> 1
// 1 -> 2
// -2 -> 3
// ... -> ...
// 2147483647 -> 4294967294
// -2147483648 -> 4294967295
//
// >> encode >>
// << decode <<
inline uint32 ZigZagEncode32(int32 n)
{
// Note: the right-shift must be arithmetic
return(n << 1) ^ (n >> 31);
}
inline int32 ZigZagDecode32(uint32 n)
{
return(n >> 1) ^ -static_cast<int32>(n & 1);
}
inline uint64 ZigZagEncode64(int64 n)
{
// Note: the right-shift must be arithmetic
return(n << 1) ^ (n >> 63);
}
inline int64 ZigZagDecode64(uint64 n)
{
return(n >> 1) ^ -static_cast<int64>(n & 1);
}
const int kMaxVarintBytes = 10;
const int kMaxVarint32Bytes = 5;
}
class CBitRead
{
uint32 m_nInBufWord;
int m_nBitsAvail;
uint32 const *m_pDataIn;
uint32 const *m_pBufferEnd;
uint32 const *m_pData;
bool m_bOverflow;
int m_nDataBits;
size_t m_nDataBytes;
static const uint32 s_nMaskTable[ 33 ]; // 0 1 3 7 15 ..
public:
CBitRead( const void *pData, int nBytes, int nBits = -1 )
{
m_bOverflow = false;
m_nDataBits = -1;
m_nDataBytes = 0;
StartReading( pData, nBytes, 0, nBits );
}
CBitRead( void )
{
m_bOverflow = false;
m_nDataBits = -1;
m_nDataBytes = 0;
}
void SetOverflowFlag( void )
{
m_bOverflow = true;
}
bool IsOverflowed( void ) const
{
return m_bOverflow;
}
int Tell( void ) const
{
return GetNumBitsRead();
}
size_t TotalBytesAvailable( void ) const
{
return m_nDataBytes;
}
int GetNumBitsLeft( void ) const
{
return m_nDataBits - Tell();
}
int GetNumBytesLeft( void ) const
{
return GetNumBitsLeft() >> 3;
}
bool Seek( int nPosition );
bool SeekRelative( int nOffset )
{
return Seek( GetNumBitsRead() + nOffset );
}
unsigned char const * GetBasePointer()
{
return reinterpret_cast< unsigned char const *>( m_pData );
}
void StartReading( const void *pData, int nBytes, int iStartBit = 0, int nBits = -1 );
int GetNumBitsRead( void ) const;
int GetNumBytesRead( void ) const;
void GrabNextDWord( bool bOverFlowImmediately = false );
void FetchNext( void );
unsigned int ReadUBitLong( int numbits );
int ReadSBitLong( int numbits );
unsigned int ReadUBitVar( void );
unsigned int PeekUBitLong( int numbits );
bool ReadBytes( void *pOut, int nBytes );
// Returns 0 or 1.
int ReadOneBit( void );
int ReadLong( void );
int ReadChar( void );
int ReadByte( void );
int ReadShort( void );
int ReadWord( void );
float ReadFloat( void );
void ReadBits( void *pOut, int nBits );
float ReadBitCoord();
float ReadBitCoordMP( EBitCoordType coordType );
float ReadBitCellCoord( int bits, EBitCoordType coordType );
float ReadBitNormal();
void ReadBitVec3Coord( Vector& fa );
void ReadBitVec3Normal( Vector& fa );
void ReadBitAngles( QAngle& fa );
float ReadBitAngle( int numbits );
float ReadBitFloat( void );
// Returns false if bufLen isn't large enough to hold the
// string in the buffer.
//
// Always reads to the end of the string (so you can read the
// next piece of data waiting).
//
// If bLine is true, it stops when it reaches a '\n' or a null-terminator.
//
// pStr is always null-terminated (unless bufLen is 0).
//
// pOutNumChars is set to the number of characters left in pStr when the routine is
// complete (this will never exceed bufLen-1).
//
bool ReadString( char *pStr, int bufLen, bool bLine=false, int *pOutNumChars = NULL );
// reads a varint encoded integer
uint32 ReadVarInt32();
uint64 ReadVarInt64();
int32 ReadSignedVarInt32() { return bitbuf::ZigZagDecode32( ReadVarInt32() ); }
int64 ReadSignedVarInt64() { return bitbuf::ZigZagDecode64( ReadVarInt64() ); }
};
#ifndef MIN
#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
#endif
#endif

28
premake/demboyz.lua Normal file
View File

@ -0,0 +1,28 @@
solution "demboyz"
basedir ".."
location (_ACTION)
startproject "demboyz"
configurations { "Debug", "Release" }
platforms "x32"
vpaths
{
["Header Files"] = { "../**.h" },
["Source Files"] = { "../**.cpp" }
}
project "demboyz"
kind "ConsoleApp"
language "C++"
files { "../demboyz/**.h", "../demboyz/**.cpp" }
configuration "Debug"
targetdir (_ACTION .. "/build/Debug")
defines { "DEBUG" }
flags { "Symbols" }
configuration "Release"
targetdir (_ACTION .. "/build/Release")
defines { "NDEBUG" }
optimize "Full"

BIN
premake/premake5.exe Normal file

Binary file not shown.

4
premake/vs2013.bat Normal file
View File

@ -0,0 +1,4 @@
premake5 --file=demboyz.lua vs2013
pause