After a few days of on/off work I have for the most part figured out the half-life sprite file format.
It would have been done faster except I kept missing the fact that even the first frame has a frame header instead of using the sprite header, anyway...
Here is what I have so far...
Code:
// Should be at the start of the file, identifies this as a sprite
const int HL_SPR_IDENTITY = ( int ) ( 'P' << 24 ) + ( 'S' << 16 ) + ( 'D' << 8 ) + ( 'I' );
// Half-life sprite file structure...
// ---------------------
// Header 42 bytes
// Palette 768 bytes
// Frame header 20 bytes
// Image data ( frame header->width * frame header->height )
// ...
// If you have more than one frame...
// Frame header 20 bytes
// Image data ( frame header->width * frame header->height )
// ...
// ... ect...
// Half-life sprite rendering modes, these determine how sprites are
// rendered by the engine.
enum hl_sprite_rendermodes_e {
SPR_MODE_NORMAL = 0, // Normal rendering
SPR_MODE_ADDITIVE, // Black ( RGB 0, 0, 0 ) is transparent
SPR_MODE_INDEXALPHA, // Last color in palette is the sprite's in-game color
SPR_MODE_ALPHATEST // Last color in palette is transparent
};
// Half-life sprite types, these determine how the sprite rotates
// when viewed by a player in-game.
enum hl_sprite_type_e {
SPR_TYPE_ROTATE_Y_ONLY = 0, // Sprite does not rotate on the X axis
SPR_TYPE_ONE_WAY, // Sprite faces one way and does not rotate ( NOTE: Not 100% sure on this )
SPR_TYPE_ROTATE_XY, // Sprite rotates to face the player on both the X and Y axis
SPR_TYPE_ONE_WAY2, // Odd, same as SPR_FACE_ONE_WAY except in a different direction
SPR_TYPE_ROTATE_XY2 // Hmm, this seemingly does the same thing as SPR_FACE_ROTATE_XY
};
// Half-life sprite header.
// Still under research.
#pragma pack( 2 )
#pragma pack( show )
typedef struct hl_sprheader_s {
char sprIdentify[ 4 ]; // 4 Character non null terminated file id. Should contain "IDSP"
int iVersion; // Sprite version number. Should be 2.
int iSpritetype; // Type of sprite
int iRendermode; // Sprite render mode. See hl_sprite_rendermodes_e.
int iUnknown4; // Offset? Actually no, it's something else...
unsigned int iWidth; // Width of sprite
unsigned int iHeight; // Height of sprite
int iFramecount; // Number of frames in sprite
int iUnknown5;
int iUnknown6;
unsigned short iUnknown7;
} hl_sprheader_t;
// This structure seems to appear at the start of a new frame within the sprite.
// NOTES:
// This is a complete structure!
// Only alter when new type/use information is found.
typedef struct hl_sprframe_s {
int iUnknown1; // Always seems to be 0
int iUnknown2; // Always seems to be C0 FF FF FF
int iUnknown3; // Always seems to be 1
unsigned int iWidth; // Width of frame
unsigned int iHeight; // Height of frame
} hl_sprframe_t;
There are quite a few unknowns but it doesn't look like they're needed to display the sprite.
But the problem I had was with the main sprite header ( hl_sprheader_t ).
What would happen is I added an unsigned short to the end of it because there are 2 still unknown bytes before the palette.
However, MSVC decided that it would make the short into 4 bytes.
That really threw everything off since the first 2 bytes of the palette were getting read into the header.
I guessed and found a solution with #pragma pack but it still doesn't feel right, can someone explain what is going on and if it will happen on a different compiler aswell?