Initial commit of Command & Conquer Renegade source code.

This commit is contained in:
LFeenanEA
2025-02-27 16:39:46 +00:00
parent 74ab8fa5e0
commit 58ed459113
4918 changed files with 1366710 additions and 0 deletions

View File

@@ -0,0 +1,242 @@
/*
** 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/>.
*/
//
// Filename: bitpacker.cpp
// Project: wwbitpack.lib
// Author: Tom Spencer-Smith
// Date: June 1998
// Description: Minimal bit encoding
//
#include "bitpacker.h"
#include <string.h> // for memset
#include "wwdebug.h"
//-----------------------------------------------------------------------------
//cBitPacker::cBitPacker(UINT buffer_size) :
cBitPacker::cBitPacker() :
//BufferSize(buffer_size),
BitWritePosition(0),
BitReadPosition(0)
{
//WWASSERT(BufferSize > 0);
//Buffer = new BYTE[BufferSize];
//WWASSERT(Buffer != NULL);
//memset(Buffer, 0, BufferSize);
memset(Buffer, 0, MAX_BUFFER_SIZE);
}
//-----------------------------------------------------------------------------
cBitPacker::~cBitPacker()
{
//delete [] Buffer;
}
//-----------------------------------------------------------------------------
cBitPacker& cBitPacker::operator=(const cBitPacker& rhs)
{
//WWASSERT(BufferSize == rhs.BufferSize);
//memcpy(Buffer, rhs.Buffer, rhs.BufferSize);
memcpy(Buffer, rhs.Buffer, MAX_BUFFER_SIZE);
BitReadPosition = rhs.BitReadPosition;
BitWritePosition = rhs.BitWritePosition;
return * this;
}
//-----------------------------------------------------------------------------
//
// This method needs optimization
//
// 02-14-2002 Jani: Optimized the code somewhat. Note that the old code reverted
// the bit order and the new one doesn't, so the versions are not compatible.
// If you use optimized Add_Bits() you need to also use optimize Get_Bits().
//
void cBitPacker::Add_Bits(ULONG value, UINT num_bits)
{
//
// N.B. Presently you cannot use this class with an atomic type of more
// than 4 bytes, such as a double. Hopefully you would be using a float
// instead anyway.
//
#if 0 // Old version
WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
ULONG mask = 1 << (num_bits - 1);
while (mask > 0) {
//WWASSERT(BitWritePosition < BufferSize * 8);
WWASSERT(BitWritePosition < MAX_BUFFER_SIZE * 8);
UINT byte_num = BitWritePosition / 8;
UINT bit_offset = BitWritePosition % 8;
bool bit_value = (value & mask) != 0;
Buffer[byte_num] |= bit_value << bit_offset;
BitWritePosition++;
mask >>= 1;
}
#else // New faster version
// Verify that we're not writing over buffer
WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
WWASSERT(BitWritePosition+num_bits <= MAX_BUFFER_SIZE * 8);
// Fill the remaining bits of the write byte first
UINT byte_num = BitWritePosition >> 3;
UINT bit_offset = BitWritePosition & 0x7;
BitWritePosition+=num_bits; // Advance the write position
// If write buffer is not byte aligned, write the remaining bits first
value <<= 32-num_bits;
if (bit_offset) {
UINT bit_count = 8 - bit_offset;
if (bit_count>num_bits) bit_count=num_bits;
ULONG bit_value = value;
value <<= bit_count; // Remove the copied bits
num_bits -= bit_count;
bit_value >>= (24+bit_offset);
Buffer[byte_num++] |= bit_value;
}
// Write the rest of the data as bytes
if (num_bits>8) {
for (unsigned a=0;a<num_bits;a+=8) {
Buffer[byte_num++]=unsigned char(value>>24);
value<<=8;
}
}
else {
Buffer[byte_num]=unsigned char(value>>24);
}
#endif
}
//-----------------------------------------------------------------------------
//
// This method needs optimization
// 02-14-2002 Jani: Optimized. See Add_Bits() for notes.
//
void cBitPacker::Get_Bits(ULONG & value, UINT num_bits)
{
#if 0 // Old version
WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
value = 0;
for (int bit = num_bits - 1; bit >= 0; bit--) {
//WWASSERT(BitReadPosition < BufferSize * 8);
WWASSERT(BitReadPosition < MAX_BUFFER_SIZE * 8);
WWASSERT(BitReadPosition < BitWritePosition);
UINT byte_num = BitReadPosition / 8;
UINT bit_offset = BitReadPosition % 8;
bool b = (Buffer[byte_num] & (1 << bit_offset)) != 0;
value += (b << bit);
BitReadPosition++;
}
#else // New faster version
// Verify that we're not reading over buffer or write pointer
WWASSERT(num_bits > 0 && num_bits <= MAX_BITS);
WWASSERT(BitReadPosition+num_bits <= MAX_BUFFER_SIZE * 8);
WWASSERT(BitReadPosition+num_bits <= BitWritePosition);
UINT read_len=num_bits;
UINT byte_num = BitReadPosition / 8;
UINT bit_offset = BitReadPosition % 8;
BitReadPosition += num_bits;
UINT bit_count = 8 - bit_offset;
if (bit_count>num_bits) bit_count=num_bits;
value = (ULONG(Buffer[byte_num++]) << (bit_offset+24));
num_bits-=bit_count;
for (int shift=24-bit_count;shift>0;shift-=8,num_bits-=8) value|=unsigned(Buffer[byte_num++]) << shift;
if (num_bits>0) value|=Buffer[byte_num++]>>(-shift);
value >>= 32-read_len;
#endif
}
//-----------------------------------------------------------------------------
//
// This method is only for use by a packet class when data is received.
//
void cBitPacker::Set_Bit_Write_Position(UINT position)
{
//WWASSERT(position <= BufferSize * 8);
WWASSERT(position <= MAX_BUFFER_SIZE * 8);
BitWritePosition = position;
}
/*
//-----------------------------------------------------------------------------
void cBitPacker::Increment_Bit_Position(int num_bits)
{
WWASSERT(num_bits >= 0);
for (int i = 0; i < num_bits; i++) {
Advance_Bit_Position();
NumBits++;
}
}
//-----------------------------------------------------------------------------
UINT cBitPacker::Get_Compressed_Size_Bytes() const
{
return (int) ceil(BitWritePosition / 8.0f);
}
//-----------------------------------------------------------------------------
inline void cBitPacker::Advance_Bit_Position()
{
BitWritePosition++;
//
// If the following assert hits then our buffer is not large enough.
// We can advance BitWritePosition one bit past the end of the buffer, but
// we cannot write there.
//
//WWASSERT(BitWritePosition < BufferSize * 8);
WWASSERT(BitWritePosition <= BufferSize * 8);
}
*/

View File

@@ -0,0 +1,98 @@
/*
** 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/>.
*/
//
// Filename: bitpacker.h
// Project: wwbitpack.lib
// Author: Tom Spencer-Smith
// Date: June 1998
// Description: Minimal bit encoding
//
#ifndef BITPACKER_H
#define BITPACKER_H
#include "always.h"
#include "bittype.h"
#pragma warning(disable:4514)
static const int MAX_BITS = 32;
// 1400 is too big. Minimum MTU allowable on the internet is 576. IP Header is 20 bytes. UDP header is 8 bytes
// So our max packet size is 576 - 28 = 548
//static const int MAX_BUFFER_SIZE = 1400;
static const int MAX_BUFFER_SIZE = 548;
class cBitPacker
{
public:
//cBitPacker(UINT buffer_size);
cBitPacker();
virtual ~cBitPacker();
char * Get_Data() const {return (char *) Buffer;}
//UINT Get_Buffer_Size() const {return BufferSize;}
UINT Get_Buffer_Size() const {return MAX_BUFFER_SIZE;}
void Flush() {BitReadPosition = BitWritePosition;}
bool Is_Flushed() const {return (BitReadPosition == BitWritePosition);}
void Add_Bits(ULONG value, UINT num_bits);
void Get_Bits(ULONG & value, UINT num_bits);
void Set_Bit_Write_Position(UINT position);
UINT Get_Bit_Write_Position() const {return BitWritePosition;}
protected:
cBitPacker& operator=(const cBitPacker& rhs);
private:
cBitPacker(const cBitPacker& source); // Disallow copy constructor
//BYTE * Buffer;
//const UINT BufferSize;
BYTE Buffer[MAX_BUFFER_SIZE];
UINT BitWritePosition;
UINT BitReadPosition;
};
#endif // BITPACKER_H
/*
void Reset() {BitWritePosition = 0;}
UINT Get_Compressed_Size_Bytes() const;
void Flush() {NumBits = 0;}
bool Is_Flushed() const {return (NumBits < 8);}
void Set_Num_Bits(int num) {WWASSERT(num >= 0); NumBits = num;}
int Get_Num_Bits(void) {return NumBits;}
void Increment_Bit_Position(int num_bits);
//inline void Advance_Bit_Position();
//int NumBits;
*/

Binary file not shown.

View File

@@ -0,0 +1,98 @@
/*
** 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/>.
*/
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : Commando *
* *
* $Archive:: /Commando/Code/wwbitpack/bitpackids.h $*
* *
* $Author:: Greg_h $*
* *
* $Modtime:: 10/14/01 11:15a $*
* *
* $Revision:: 6 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#ifndef BITPACKIDS_H
#define BITPACKIDS_H
enum {
/*
//
// 08/30/00 Use of pathfind extents for bitcompression decommissioned.
// Flying vehicles and sea vehicles would have to use world extents
// anyway.
//
//
// Use these for objects restricted to pathfindable areas
//
BITPACK_PATHFIND_POSITION_X,
BITPACK_PATHFIND_POSITION_Y,
BITPACK_PATHFIND_POSITION_Z,
*/
//
// Use these for objects restricted to world extents
//
BITPACK_WORLD_POSITION_X,
BITPACK_WORLD_POSITION_Y,
BITPACK_WORLD_POSITION_Z,
BITPACK_ONE_TIME_BOOLEAN_BITS,
BITPACK_CONTINUOUS_BOOLEAN_BITS,
BITPACK_ANALOG_VALUES,
BITPACK_HEALTH,
BITPACK_SHIELD_STRENGTH,
BITPACK_SHIELD_TYPE,
BITPACK_CTF_TEAM_FLAG,
BITPACK_HUMAN_STATE,
BITPACK_HUMAN_SUB_STATE,
BITPACK_VEHICLE_VELOCITY,
BITPACK_VEHICLE_ANGULAR_VELOCITY,
BITPACK_VEHICLE_QUATERNION,
BITPACK_VEHICLE_LOCK_TIMER,
BITPACK_DOOR_STATE,
BITPACK_ELEVATOR_STATE,
BITPACK_ELEVATOR_TOP_DOOR_STATE,
BITPACK_ELEVATOR_BOTTOM_DOOR_STATE,
BITPACK_BUILDING_RADIUS,
BITPACK_BUILDING_STATE,
BITPACK_CONTROL_MOVES_CS,
BITPACK_CONTROL_MOVES_SC,
BITPACK_PACKET_TYPE,
BITPACK_PACKET_ID,
};
#endif // BITPACKIDS_H

View File

@@ -0,0 +1,242 @@
/*
** 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.cpp $*
* *
* Original Author:: Tom Spencer-Smith *
* *
* $Author:: Bhayes $*
* *
* $Modtime:: 2/18/02 10:49p $*
* *
* $Revision:: 4 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "bitstream.h"
#include <string.h> // for strlen
#include <math.h> // for ceil
#include "wwdebug.h"
#include "mathutil.h"
#include "widestring.h"
//-----------------------------------------------------------------------------
BitStreamClass::BitStreamClass() :
cBitPacker(),
UncompressedSizeBytes(0)
{
}
//-----------------------------------------------------------------------------
BitStreamClass& BitStreamClass::operator=(const BitStreamClass& rhs)
{
//
// Call operator for base class
//
cBitPacker::operator= (rhs);
UncompressedSizeBytes = rhs.UncompressedSizeBytes;
return * this;
}
//-----------------------------------------------------------------------------
void BitStreamClass::Add(bool value)
{
if (cEncoderList::Is_Compression_Enabled()) {
Add_Bits(value, 1);
} else {
Add_Bits(value, BIT_DEPTH(bool));
}
UncompressedSizeBytes += BYTE_DEPTH(bool);
}
//-----------------------------------------------------------------------------
bool BitStreamClass::Get(bool & value)
{
ULONG u_value;
if (cEncoderList::Is_Compression_Enabled()) {
Get_Bits(u_value, 1);
} else {
Get_Bits(u_value, BIT_DEPTH(bool));
}
value = (u_value == 1);
return value;
}
//-----------------------------------------------------------------------------
void BitStreamClass::Add_Raw_Data(LPCSTR data, USHORT data_size)
{
WWASSERT(data != NULL);
WWASSERT(data_size >= 0);
for (int i = 0; i < data_size; i++) {
Add(data[i]);
}
}
//-----------------------------------------------------------------------------
void BitStreamClass::Get_Raw_Data(char * buffer, USHORT buffer_size, USHORT data_size)
{
WWASSERT(buffer != NULL);
WWASSERT(data_size >= 0);
WWASSERT(buffer_size >= data_size);
for (int i = 0; i < data_size; i++) {
Get(buffer[i]);
}
}
//-----------------------------------------------------------------------------
void BitStreamClass::Add_Terminated_String(LPCSTR string, bool permit_empty)
{
WWASSERT(string != NULL);
//
// The terminating null is not transmitted.
//
USHORT len = (USHORT) strlen(string);
if (!permit_empty) {
WWASSERT(len > 0);
}
Add(len);
for (int i = 0; i < len; i++) {
Add(string[i]);
}
}
//-----------------------------------------------------------------------------
void BitStreamClass::Get_Terminated_String(char * buffer, USHORT buffer_size, bool permit_empty)
{
WWASSERT(buffer != NULL);
WWASSERT(buffer_size > 0);
USHORT len;
Get(len);
WWASSERT(len < buffer_size);
if (!permit_empty) {
WWASSERT(len > 0);
}
char temp = '?';
int i = 0;
for (i = 0; i < len; i++) {
Get(temp);
if (i < buffer_size - 1) {
buffer[i] = temp;
}
}
// Null-terminate it.
if (i < buffer_size) {
buffer[i] = 0;
} else {
buffer[buffer_size - 1] = 0;
}
}
//-----------------------------------------------------------------------------
void BitStreamClass::Add_Wide_Terminated_String(const WCHAR *string, bool permit_empty)
{
WWASSERT(string != NULL);
//
// The terminating null is not transmitted.
//
USHORT len = (USHORT)wcslen (string);
if (!permit_empty) {
WWASSERT(len > 0 && "Empty string not permitted");
}
Add(len);
for (int i = 0; i < len; i++) {
Add(string[i]);
}
}
//-----------------------------------------------------------------------------
void BitStreamClass::Get_Wide_Terminated_String(WCHAR *buffer, USHORT buffer_len, bool permit_empty)
{
WWASSERT(buffer != NULL);
WWASSERT(buffer_len > 0);
USHORT len;
Get(len);
WWASSERT(len < buffer_len && "String length exceeds provided buffer");
if (!permit_empty) {
WWASSERT(len > 0 && "Empty string not permitted");
}
WCHAR temp = L'?';
int i = 0;
for (i = 0; i < len; i++) {
Get(temp);
if (i < buffer_len - 1) {
buffer[i] = temp;
}
}
if (i < buffer_len - 1) {
buffer[i] = 0; // Null-terminate it.
} else {
buffer[buffer_len-1] = 0;
}
}
//-----------------------------------------------------------------------------
UINT BitStreamClass::Get_Compressed_Size_Bytes() const
{
return (UINT) ceil(Get_Bit_Write_Position() / 8.0f);
}
//-----------------------------------------------------------------------------
UINT BitStreamClass::Get_Compression_Pc() const
{
UINT c_size = Get_Compressed_Size_Bytes();
UINT u_size = Get_Uncompressed_Size_Bytes();
if (cEncoderList::Is_Compression_Enabled()) {
WWASSERT(c_size <= u_size);
} else {
WWASSERT(c_size == u_size);
}
WWASSERT(u_size > 0);
UINT compression_pc = (UINT) cMathUtil::Round(100 * c_size / (float) u_size);
WWASSERT(compression_pc >= 0 && compression_pc <= 100);
return compression_pc;
}

220
Code/wwbitpack/bitstream.h Normal file
View File

@@ -0,0 +1,220 @@
/*
** 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

View File

@@ -0,0 +1,52 @@
/*
** 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/>.
*/
//
// Filename: encoderlist.cpp
// Project: wwbitpack.lib
// Author: Tom Spencer-Smith
// Date: June 1998
// Description:
//
#include "encoderlist.h"
#include "wwdebug.h"
//
// Class statics
//
bool cEncoderList::IsCompressionEnabled = true;
cEncoderTypeEntry cEncoderList::EncoderTypes[];
//-----------------------------------------------------------------------------
void cEncoderList::Clear_Entries()
{
WWDEBUG_SAY(("cEncoderList::Clear_Entries\n"));
for (int i = 0; i < MAX_ENCODERTYPES; i++) {
EncoderTypes[i].Invalidate();
}
}
//-----------------------------------------------------------------------------
cEncoderTypeEntry & cEncoderList::Get_Encoder_Type_Entry(int index)
{
WWASSERT(index >= 0 && index < MAX_ENCODERTYPES);
return EncoderTypes[index];
}

View File

@@ -0,0 +1,98 @@
/*
** 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/>.
*/
//
// Filename: encoderlist.h
// Project: wwbitpack.lib
// Author: Tom Spencer-Smith
// Date: June 1998
// Description:
//
#ifndef ENCODERLIST_H
#define ENCODERLIST_H
#include "encodertypeentry.h"
#include "miscutil.h"
#include "wwdebug.h"
const int MAX_ENCODERTYPES = 100;
class cEncoderList
{
public:
static void Clear_Entries();
static void Set_Compression_Enabled(bool flag) {IsCompressionEnabled = flag;}
static bool Is_Compression_Enabled() {return IsCompressionEnabled;}
static cEncoderTypeEntry & Get_Encoder_Type_Entry(int index);
#pragma auto_inline(off)
//------------------------------------------------------------------------------------
template<class T> static T Set_Precision(int type, T min, T max,
T resolution = 1)
{
WWASSERT(type >= 0 && type < MAX_ENCODERTYPES);
WWASSERT(max - min > -MISCUTIL_EPSILON);
WWASSERT(resolution > MISCUTIL_EPSILON);
EncoderTypes[type].Init(
static_cast<double>(min),
static_cast<double>(max),
static_cast<double>(resolution));
WWDEBUG_SAY(("cEncoderList::Set_Precision for type %d: %d -> %d bits\n",
type, sizeof(T) * 8, EncoderTypes[type].Get_Bit_Precision()));
//
// Return maximum representation error
//
return static_cast<T>(resolution / 2.0f + MISCUTIL_EPSILON);
/*
double max_error = EncoderTypes[type].Get_Resolution() / 2.0f + MISCUTIL_EPSILON;
if (::fabs(max_error - static_cast<T>(max_error)) < MISCUTIL_EPSILON) {
//return static_cast<T>(max_error);
return static_cast<T>(max_error);
} else {
return static_cast<T>(ceil(max_error));
}
/**/
}
//------------------------------------------------------------------------------------
static void Set_Precision(int type, int num_bits)
{
WWASSERT(type >= 0 && type < MAX_ENCODERTYPES);
WWASSERT(num_bits > 0 && num_bits <= 32);
EncoderTypes[type].Init(num_bits);
WWDEBUG_SAY(("cEncoderList::Set_Precision for type %d: %d bits\n",
type, num_bits));
}
//------------------------------------------------------------------------------------
#pragma auto_inline(on)
private:
static cEncoderTypeEntry EncoderTypes[MAX_ENCODERTYPES];
static bool IsCompressionEnabled;
};
#endif // ENCODERLIST_H

View File

@@ -0,0 +1,186 @@
/*
** 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/>.
*/
//
// Filename: encodertypeentry.cpp
// Project: wwbitpack.lib
// Author: Tom Spencer-Smith
// Date: June 2000
// Description:
//
//-----------------------------------------------------------------------------
#include "encodertypeentry.h" // I WANNA BE FIRST!
#include <math.h>
#include <limits.h>
#include "wwdebug.h"
#include "miscutil.h"
#include "mathutil.h"
static const int MAX_BITS = 32;
//-----------------------------------------------------------------------------
cEncoderTypeEntry::cEncoderTypeEntry()
{
Invalidate();
}
//-----------------------------------------------------------------------------
bool cEncoderTypeEntry::Is_Valid() const
{
return
((Max - Min > -MISCUTIL_EPSILON) &&
(Resolution > -MISCUTIL_EPSILON) &&
(BitPrecision >= 0));
}
//-----------------------------------------------------------------------------
void cEncoderTypeEntry::Invalidate()
{
Min = 1;
Max = -1;
Resolution = -1;
BitPrecision = 0;
}
//-----------------------------------------------------------------------------
bool cEncoderTypeEntry::Is_Value_In_Range(double value) const
{
return (value >= Min - MISCUTIL_EPSILON && value <= Max + MISCUTIL_EPSILON);
}
//-----------------------------------------------------------------------------
void cEncoderTypeEntry::Init(double min, double max, double resolution)
{
WWASSERT(!Is_Valid());
WWASSERT(max - min > -MISCUTIL_EPSILON);
WWASSERT(resolution > MISCUTIL_EPSILON);
Min = min;
Max = max;
Calc_Bit_Precision(resolution);
WWASSERT(Is_Valid());
}
//-----------------------------------------------------------------------------
void cEncoderTypeEntry::Init(int num_bits)
{
WWASSERT(!Is_Valid());
WWASSERT(num_bits > 0 && num_bits <= 32);
Min = 0;
BitPrecision = num_bits;
Resolution = 1;
UINT max = 0;
for (int i = 0; i < num_bits; i++) {
max += 1 << i;
}
Max = max;
WWASSERT(Is_Valid());
}
//-----------------------------------------------------------------------------
bool cEncoderTypeEntry::Scale(double value, ULONG & scaled_value)
{
WWASSERT(Is_Valid());
bool is_in_range = Is_Value_In_Range(value);
if (!is_in_range) {
value = Clamp(value);
}
scaled_value = static_cast<ULONG>
(cMathUtil::Round((value - Min) / Resolution));
return is_in_range;
}
//-----------------------------------------------------------------------------
double cEncoderTypeEntry::Unscale(ULONG u_value)
{
WWASSERT(Is_Valid());
double value = Min + u_value * Resolution;
WWASSERT(Is_Value_In_Range(value));
return value;
}
//-----------------------------------------------------------------------------
double cEncoderTypeEntry::Clamp(double value)
{
WWASSERT(Is_Valid());
double retval = value;
if (retval < Min) {
retval = Min;
} else if (retval > Max) {
retval = Max;
}
return retval;
}
//-----------------------------------------------------------------------------
void cEncoderTypeEntry::Calc_Bit_Precision(double resolution)
{
//
// Calculate the minimum number of bits required to encode this type with
// the specified resolution.
//
WWASSERT(Max - Min > -MISCUTIL_EPSILON);
WWASSERT(resolution > MISCUTIL_EPSILON);
double f_units = (double) ceil((Max - Min) / resolution - MISCUTIL_EPSILON) + 1;
WWASSERT(f_units <= UINT_MAX + MISCUTIL_EPSILON);
UINT units = (UINT) f_units;
BitPrecision = 0;
UINT max_units = 0;
while (max_units < units) {
max_units += 1 << BitPrecision;
BitPrecision++;
if (BitPrecision == 1) {
max_units++;
}
}
WWASSERT(BitPrecision > 0 && BitPrecision <= MAX_BITS);
WWASSERT(max_units > 0);
Resolution = (Max - Min) / (double) (max_units - 1);
/*TSS2001
if (Resolution > 0) {
WWASSERT(max_units ==
(UINT) ceil((Max - Min) / Resolution - MISCUTIL_EPSILON) + 1);
}
*/
}

View File

@@ -0,0 +1,68 @@
/*
** 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/>.
*/
//
// Filename: encodertypeentry.h
// Project: wwbitpack.lib
// Author: Tom Spencer-Smith
// Date: June 2000
// Description:
//
//-----------------------------------------------------------------------------
#if defined(_MSV_VER)
#pragma once
#endif
#ifndef ENCODERTYPEENTRY_H
#define ENCODERTYPEENTRY_H
#include "bittype.h"
class cEncoderTypeEntry
{
public:
cEncoderTypeEntry::cEncoderTypeEntry();
void Init(double min, double max, double resolution);
void Init(int num_bits);
bool Scale(double value, ULONG & scaled_value);
double Unscale(ULONG u_value);
double Clamp(double value);
UINT Get_Bit_Precision() const {return BitPrecision;}
double Get_Resolution() const {return Resolution;}
bool Is_Valid() const;
void Invalidate();
bool Is_Value_In_Range(double value) const;
private:
cEncoderTypeEntry(const cEncoderTypeEntry& source); // Disallow
cEncoderTypeEntry& operator=(const cEncoderTypeEntry& rhs); // Disallow
void Calc_Bit_Precision(double resolution);
double Min;
double Max;
double Resolution;
UINT BitPrecision;
};
#endif // ENCODERTYPEENTRY_H

View File

@@ -0,0 +1,147 @@
# Microsoft Developer Studio Project File - Name="wwbitpack" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=wwbitpack - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "wwbitpack.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "wwbitpack.mak" CFG="wwbitpack - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "wwbitpack - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "wwbitpack - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE "wwbitpack - Win32 Profile" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/Commando/Code/wwbitpack", JAQDAAAA"
# PROP Scc_LocalPath "."
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "wwbitpack - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W4 /WX /Zi /O2 /Ob2 /I "..\wwlib" /I "..\wwdebug" /I "..\wwutil" /D "NDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"..\libs\Release\wwbitpack.lib"
!ELSEIF "$(CFG)" == "wwbitpack - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W4 /WX /Gm /Gi /ZI /Od /I "..\wwlib" /I "..\wwdebug" /I "..\wwutil" /D "_DEBUG" /D "WWDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /YX /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo /out:"..\libs\Debug\wwbitpack.lib"
!ELSEIF "$(CFG)" == "wwbitpack - Win32 Profile"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Profile"
# PROP BASE Intermediate_Dir "Profile"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Profile"
# PROP Intermediate_Dir "Profile"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W4 /WX /GX /O2 /I "..\wwlib" /I "..\wwdebug" /I "..\wwutil" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
# ADD CPP /nologo /MT /W4 /WX /Zi /O2 /Op /Ob2 /I "..\wwlib" /I "..\wwdebug" /I "..\wwutil" /D "NDEBUG" /D "WWDEBUG" /D WINVER=0x400 /D "_WINDOWS" /D "WIN32_LEAN_AND_MEAN" /D "WIN32" /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo /out:"..\libs\Release\wwbitpack.lib"
# ADD LIB32 /nologo /out:"..\libs\Profile\wwbitpack.lib"
!ENDIF
# Begin Target
# Name "wwbitpack - Win32 Release"
# Name "wwbitpack - Win32 Debug"
# Name "wwbitpack - Win32 Profile"
# Begin Source File
SOURCE=.\BitPacker.cpp
# End Source File
# Begin Source File
SOURCE=.\BitPacker.h
# End Source File
# Begin Source File
SOURCE=.\bitpackids.h
# End Source File
# Begin Source File
SOURCE=.\bitstream.cpp
# End Source File
# Begin Source File
SOURCE=.\bitstream.h
# End Source File
# Begin Source File
SOURCE=.\encoderlist.cpp
# End Source File
# Begin Source File
SOURCE=.\encoderlist.h
# End Source File
# Begin Source File
SOURCE=.\encodertypeentry.cpp
# End Source File
# Begin Source File
SOURCE=.\encodertypeentry.h
# End Source File
# End Target
# End Project