Blowing My Foot Off

After a few days of not being able to get Chimera to compile because of some seemingly obtuse compiler error, I’ve finally got it building and it was down to a schoolboy error.

I have a pure virtual base class called GameObject, from which I derive objects like Entity, Player and Block. The compiler kept telling me that I couldn’t instantiate Player, because it was an abstract class.

I looked at the GameObject class over and over and couldn’t see what was wrong.

class GameObject
{
public:
virtual ~GameObject();
virtual void update(float) = 0;
virtual void draw() const = 0;

protected:
ci::Vec3f position_;
ci::Vec3f size_;
};

Well take a look at that const. Looks innocuous enough, but in the classes I decided to over-ride draw() for, I forgot to use the const, which meant that as far as the compiler was concerned, I hadn’t implemented that exact function. And of course, I hadn’t. Took me ages to spot, but the compiler was right and I just wasn’t looking hard enough.

The Boost Library

chimera-and-boost-library.jpg

I’ve been struggling for a while with indecision. At first I wanted to write an event system from scratch. Then I got sidetracked somewhat by McShaffry’s Game Coding Complete (bought in Kindle format and read on iPad). I’ve been doing an awful lot of C++ reading and I’m not ashamed to admit that much of it (certainly at first) seemed beyond me. Some of the things people get templates to do are just dizzying.

The upshot is that after much vacillation, I decided to use boost::signal. That’s when the real problems began. I tried search after search and found that I couldn’t get the basics done no matter what.  I read all kinds of distracting advice on what the problems might be, but ultimately realised that the issue I was facing was somewhat more fundamental. The scripts that build boost weren’t finding G++. It finally dawned on me that the build tools weren’t set up properly. So I installed the latest release of Xcode 4 and this time, told it to include the Unix tools. Now bjam was finding G++, but still not working.

It was just as well that I’d already given up last night and decided to simply drag the files from the signal source directory directly into my Xcode project. Everything worked fine after that. It’s worth mentioning that much of boost doesn’t require libraries, as everything you need is in the header files. There are some boost classes that do require building into a library, and boost::signal is one of those classes.

There really should be a binary distribution of a library as important as boost for Mac OS X and I’m surprised at how poor the state of support is.

Still, back to Chimera now – and how energy conservation can be turned into a game mechanic. I’m also thinking about the revision of history as a game concept and the notion of redemption as a gameplay mechanic. Yeah, I’m serious. This is a game after all.

(By the way, I particularly enjoyed reading this perspective on Chimera).

 

Gory Detail

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 = 0x80;

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 : 0x80;

–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.