This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/wwbitpack/bitstream.h

221 lines
8.5 KiB
C
Raw Permalink Normal View History

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** 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, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : wwbitpack *
* *
* $Archive:: /Commando/Code/wwbitpack/bitstream.h $*
* *
* Original Author:: Tom Spencer-Smith *
* *
* $Author:: Patrick $*
* *
* $Modtime:: 6/13/01 9:05a $*
* *
* $Revision:: 3 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BITSTREAM_H
#define BITSTREAM_H
#include "bitpacker.h"
#include "wwdebug.h"
#include "encoderlist.h"
#include "mathutil.h"
#include "math.h"
#include "widestring.h"
#define BYTE_DEPTH(x) (sizeof(x))
#define BIT_DEPTH(x) (8 * sizeof(x))
/**
** BitStreamClass
**
** Author: Tom Spencer-Smith
** Date: June 1998
** Description: A class for minimal bit encoding.
** Notes:
** - Uncompressed data may be included in the bitstream.
** - Compression may be disabled entirely if desired.
** - Bools are compressed to 1 bit without requiring a precision
** setup.
** - Strings and raw data are uncompressed.
**
** (gth, 08/31/2000) - renamed this class to BitStreamClass (from cTypeEncoder) and
** cleaned it up to become the interface that all game and library code uses to
** package up their state variables for network transmission, converted to westwood
** naming convention since it is going to propogate to a lot of other code.
*/
class BitStreamClass : public cBitPacker
{
public:
BitStreamClass();
BitStreamClass& operator=(const BitStreamClass& rhs);
UINT Get_Uncompressed_Size_Bytes() const {return UncompressedSizeBytes;}
UINT Get_Compressed_Size_Bytes() const;
UINT Get_Compression_Pc() const;
//
// For data which may include NULL's.
// Data will not be compressed.
//
void Add_Raw_Data(LPCSTR data, USHORT data_size);
void Get_Raw_Data(char * buffer, USHORT buffer_size, USHORT data_size);
//
// For data terminated with NULL.
// Data will not be compressed.
// You may permit or disallow empty strings to be passed.
//
void Add_Terminated_String(LPCSTR string, bool permit_empty = false);
void Get_Terminated_String(char * buffer, USHORT buffer_size, bool permit_empty = false);
//
// For data terminated with NULL.
// Data will not be compressed.
// You may permit or disallow empty strings to be passed.
//
void Add_Wide_Terminated_String(const WCHAR *string, bool permit_empty = false);
void Get_Wide_Terminated_String (WCHAR *buffer, USHORT buffer_len, bool permit_empty = false);
//
// Bool is special-cased because we know that we can always
// represent it as 1 bit.
//
void Add(bool value);
bool Get(bool & value);
//
// For all other data types that we want to support, call into our internal
// template function.
//
enum {NO_ENCODER = -1};
void Add(BYTE val,int type = NO_ENCODER) { Internal_Add(val,type); }
void Add(USHORT val,int type = NO_ENCODER) { Internal_Add(val,type); }
void Add(UINT val,int type = NO_ENCODER) { Internal_Add(val,type); }
void Add(ULONG val,int type = NO_ENCODER) { Internal_Add(val,type); }
void Add(char val,int type = NO_ENCODER) { Internal_Add(val,type); }
void Add(int val,int type = NO_ENCODER) { Internal_Add(val,type); }
void Add(float val,int type = NO_ENCODER) { Internal_Add(val,type); }
BYTE Get(BYTE & set_val,int type = NO_ENCODER) { return Internal_Get(set_val,type); }
USHORT Get(USHORT & set_val,int type = NO_ENCODER) { return Internal_Get(set_val,type); }
ULONG Get(ULONG & set_val,int type = NO_ENCODER) { return Internal_Get(set_val,type); }
UINT Get(UINT & set_val,int type = NO_ENCODER) { return Internal_Get(set_val,type); }
char Get(char & set_val,int type = NO_ENCODER) { return Internal_Get(set_val,type); }
int Get(int & set_val,int type = NO_ENCODER) { return Internal_Get(set_val,type); }
float Get(float & set_val,int type = NO_ENCODER) { return Internal_Get(set_val,type); }
private:
//
// Add/Get for remaining atomic data types.
// I really wish the following 3 methods were in the source file, but
// the compiler won't accept this. Hopefully the pragma and MSVC
// will prevent inlining.
//
#pragma auto_inline(off)
//------------------------------------------------------------------------------------
template<class T> void Internal_Add(T value, int type = NO_ENCODER) {
if (cEncoderList::Is_Compression_Enabled() && type != NO_ENCODER) {
WWASSERT(type >= 0 && type < MAX_ENCODERTYPES);
cEncoderTypeEntry & entry = cEncoderList::Get_Encoder_Type_Entry(type);
//
// If the following assert hits then the value of the type
// parameter is unknown.
//
WWASSERT(entry.Is_Valid());
ULONG scaled_value;
bool is_in_range = entry.Scale(value, scaled_value);
if (!is_in_range) {
//WWDEBUG_SAY(("BitStreamClass::Add : Warning: out-of-range value clamped (type %d).\n",
// type));
//DIE;
}
Add_Bits(scaled_value, entry.Get_Bit_Precision());
} else {
Add_Bits(*(reinterpret_cast<ULONG *>(&value)), BIT_DEPTH(T));
}
UncompressedSizeBytes += BYTE_DEPTH(T);
}
//------------------------------------------------------------------------------------
template<class T> T Internal_Get(T & value, int type = NO_ENCODER) {
if (cEncoderList::Is_Compression_Enabled() && type != NO_ENCODER) {
WWASSERT(type >= 0 && type < MAX_ENCODERTYPES);
cEncoderTypeEntry & entry = cEncoderList::Get_Encoder_Type_Entry(type);
//
// If the following assert hits then the value of the type
// parameter is unknown.
//
WWASSERT(entry.Is_Valid());
ULONG u_value;
Get_Bits(u_value, entry.Get_Bit_Precision());
double f_value = entry.Unscale(u_value);
if ((::fabs(f_value - static_cast<T>(f_value)) < MISCUTIL_EPSILON)) {
//
// N.B. More error may be introduced here
//
value = static_cast<T>(f_value);
} else {
value = static_cast<T>(cMathUtil::Round(f_value));
}
WWASSERT(entry.Is_Value_In_Range(value));
} else {
ULONG u_value;
Get_Bits(u_value, BIT_DEPTH(T));
value = *(reinterpret_cast<T *>(&u_value));
}
return value;
}
//------------------------------------------------------------------------------------
#pragma auto_inline(on)
UINT UncompressedSizeBytes; // for statistics only
};
#endif // TYPEENCODER_H