Here then, in all its gory detail, is the the file I’ve been working on this evening. Most of my time was wasted in trying to work out how the vector class worked and getting to the bottom of arcane compiler errors. Stuff like having to include std:: to qualify the vectors I was using, and getting the template for my really bare bones simple Colour class right. Sheesh, if I was doing this game in assembler or C, I would have finished it by now, but I know I’ll reap the benefits of proper C++ if I stick with it and let it do some of the heavy lifting for me.
And yes, I know the tabs have been stripped, just be grateful there are colours here.
/*what does this class do?
given a character pointer, it constructs a 2D array of RGBA from bitmap data of varying bit depths
what are the parameters?
width, height of source
bpp of source
palette to use when mapping to RGBA
stride per byte
stride per line
endianness
width of pixel group (in bits)
What’s the real world use of this class?
This class is used to decode old school bit streams of graphics data and
turn them into displayable blocks for capture and re-use in modern environments.
*/
#include “common.h”
#include <vector>
class StreamToImage {
public:
StreamToImage();
virtual ~StreamToImage ();
void setParams(int, int, int, int); // width, height, stride per byte, stride per line
void setWidth(int);
void setHeight(int);
void setStrideByte(int);
void setStrideLine(int);
bool setPalette(std::vector<Colour<BYTE> > *, int); // palette pointer and size of palette
bool extract(BYTE *); // extract to internal buffer given pointer to raw byte stream
void copyPixelBuffer(std::vector< Colour<BYTE> > *);
protected:
int width;
int height;
int strideByte;
int strideLine;
int bitsPerPixel;
std::vector<Colour<BYTE> > palette;
protected:
bool extract1BitPerPixel(BYTE *rawDataStream);
bool extract2BitsPerPixel(BYTE *rawDataStream);
private:
std::vector< Colour<BYTE> > pixels;
bool goodToGo;
};
StreamToImage::StreamToImage()
{
// Make the entire palette black, but set alpha to max
for (int i = 0; i < palette.size(); i++)
{
palette[i].r = palette[i].g = palette[i].b = 0;
palette[i].a = 0xFF;
}
palette[1].r = palette[1].g = palette[1].b = 0xff; // Make 1st palette colour white
bitsPerPixel = 1;
goodToGo = FALSE;
}
void copyPixelBuffer(std::vector< Colour<BYTE> > *pDest)
{
*pDest = pixels;
}
void StreamToImage::setParams(int w, int h, int sB, int sL)
{
width = w;
height = h;
strideByte = sB;
strideLine = sL;
goodToGo = TRUE;
}
StreamToImage::~StreamToImage()
{
}
inline void StreamToImage::setWidth(int w)
{
width = w;
}
inline void StreamToImage::setHeight(int h)
{
height = h;
}
inline void StreamToImage::setStrideByte(int s)
{
strideByte = s;
}
inline void StreamToImage::setStrideLine(int s)
{
strideLine = s;
}
bool StreamToImage::setPalette(std::vector<Colour<BYTE> > *p, int numPaletteEntries)
{
if (numPaletteEntries > kMaxPaletteEntries)
return FALSE;
palette = *p;
return TRUE;
}
bool StreamToImage::extract(BYTE *rawDataStream)
{
if (!goodToGo)
return FALSE;
// We have a palette and all the vars are set up, time to extract to our internal buffer
switch (bitsPerPixel)
{
case 1: // Monochromatic spectrum
return extract1BitPerPixel(rawDataStream);
case 2: // Commodore 64 or Amstrad
return extract2BitsPerPixel(rawDataStream);
default:
return FALSE;
}
}
bool StreamToImage::extract1BitPerPixel(BYTE *rawDataStream)
{
BYTE *pb;
BYTE bit;
for (int y = 0; y < height; y++)
{
BYTE mask = 0×80;
BYTE shift = 7;
for (int x = 0; x < width; x++)
{
byte = pb[y * strideLine + (x >> 3)];
bit = (byte & mask) >> shift;
// Now we have a value for the bit, use the palette index 1 to set it in our pixel buffer
pixels[x + y * width] = palette[1];
mask >>= 1 ? mask : 0×80;
–shift ? shift : 7;
}
}
return TRUE;
}
bool StreamToImage::extract2BitsPerPixel(BYTE *rawDataStream)
{
return FALSE;
}
I accept that constructs like the bool “goodToGo” have no place in polite society. I felt a little dirty doing that. I also think the ternary operators resetting the mask and shift values are a cop-out. I ain’t fooling anyone with that pitiful attempt to hide two branches in the middle of a byte loop, but the engines can take it captain. At least, they can nowadays.
Ugly, isn’t it? Go on, give me tips. I can and will improve this, but you can see what I’m trying to do here.