Hi,
I’ve been coding a game using SDL in C++ lately, and just like
probably everyone else, I’ve hacked up some C++ SDL wrappers. However,
what I’ve produced aren’t strictly wrappers, there’s some
"value-added" functionality like
- arbitrary affine transformations (stretching, rotation, shearing)
on surfaces - graphics primitives (polygon, line, box, circle, ellipse)
filled and non-filled - tiling
- an audio manager (i.e. you can add some streams to that manager,
and it will take care of samplerate conversion and mixing for you) - bitmap fonts (may be prerendered from ttfs)
- png loading
My wrappers depend on ixlib, which is a generic LGPL tools library.
I’ve included the relevant header files as attachments, FYI. Please
note, this isn’t just a header proposal, there’s actual tested code
behind all this.
I’d like to know whether there’s interest in such wrapper classes and
whether it would be a valuable job to separate this code out into a
library for public consumption, taking into account that we already
have SDL–. (http://sdlmm.sf.net/)
Andreas
-------------- next part --------------
// ----------------------------------------------------------------------------
// Description : SDL video wrappers
// ----------------------------------------------------------------------------
// Remarks : none.
//
// ----------------------------------------------------------------------------
// © Copyright 1999 by Team WAM
// ----------------------------------------------------------------------------
#ifndef WAM_SDL_VIDEO
#define WAM_SDL_VIDEO
#include
#include
#include <ixlib_xml.hh>
#include <ixlib_geometry.hh>
#include <ixlib_polygon.hh>
#include “output/sdl_base.hh”
// wSurface -------------------------------------------------------------------
class wFont;
struct wAffineTransformation {
double Matrix[2][2];
double Translation[2];
void identity();
void translate(double x,double y);
void scale(double x,double y);
void rotate(double rad);
void invert();
void transform(double &dest_x,double &dest_y,double x,double y) const;
void transformLinear(double &dest_x,double &dest_y,double x,double y) const;
};
class wSurface {
public:
enum TTextAlignment {
ALIGN_TOP,ALIGN_BASE,ALIGN_BOTTOM
};
enum TDrawMode {
COLOR,
TILE,
IMAGE,
};
typedef Uint32 TColor;
typedef Sint32 TCoordinate;
SDL_Surface *Surface;
protected:
// printing text
TCoordinate CursorX;
TCoordinate CursorY;
TDelta LineDistance;
TTextAlignment TextAlignment;
bool FreeMem;
TCoordinate ReferencePointX;
TCoordinate ReferencePointY;
TDrawMode DrawMode;
TColor DrawColor;
const wSurface *DrawTile,*PixelImage;
TCoordinate TileZeroX,TileZeroY;
public:
wSurface();
wSurface(SDL_PixelFormat const &fmt,TSize width,TSize height,
Uint32 flags = SDL_SWSURFACE);
wSurface(wSurface const &src,double stretchx = 1,double stretchy = 1,double rotate = 0);
wSurface(wSurface const &src,wAffineTransformation const &tx);
wSurface(SDL_Surface *surface, bool freemem = false);
~wSurface();
void setSurface(SDL_Surface *surface, bool freemem = false);
void load(istream &datastrm);
void save(ostream &datastrm);
TColor mapRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a = SDL_ALPHA_OPAQUE);
void unmapRGBA(TColor color,Uint8 &r,Uint8 &g,Uint8 &b,Uint8 &a);
TSize getHeight() const {
return Surface->h;
}
TSize getWidth() const {
return Surface->w;
}
Uint32 getFlags() const {
return Surface->flags;
}
TCoordinate getReferencePointX() const {
return ReferencePointX;
}
TCoordinate getReferencePointY() const {
return ReferencePointY;
}
rectangle<wSurface::TCoordinate> getExtent() const;
bool hasColorKey() const;
TColor getColorKey() const;
void setColorKey(TColor key,Uint32 flags = SDL_SRCCOLORKEY);
void clearColorKey();
bool hasAlphaChannel() const;
bool hasSurfaceAlpha() const;
void setAlphaFlags(Uint32 flags = SDL_SRCALPHA,Uint8 alpha = SDL_ALPHA_OPAQUE);
void ignoreAlpha();
SDL_Rect const &getClipping() {
return Surface->clip_rect;
}
void setClipping(SDL_Rect &rect);
void clearClipping();
SDL_PixelFormat const &getDisplayFormat() const;
wSurface *convert(SDL_PixelFormat const &fmt,Uint32 flags) const;
wSurface *convertToDisplay() const;
wSurface *convertForAcceleratedBlit() const;
// low-level
TColor getDrawColor() const;
void setDrawColor(TColor color);
wSurface const *getDrawTile() const;
void setDrawTile(wSurface const *tile,TCoordinate zerox = 0,TCoordinate zeroy = 0);
wSurface const *getPixelImage() const;
void setPixelImage(wSurface const *pixel);
TColor getPixel(TCoordinate x,TCoordinate y);
void setPixel(TCoordinate x,TCoordinate y);
void drawHLine(TCoordinate x1,TCoordinate y,TCoordinate x2);
void drawVLine(TCoordinate x,TCoordinate y1,TCoordinate y2);
// high-level
void drawLine(TCoordinate x1,TCoordinate y1,TCoordinate x2,TCoordinate y2);
void drawBox(TCoordinate x1,TCoordinate y1,TCoordinate x2,TCoordinate y2);
void fillBox(TCoordinate x1,TCoordinate y1,TCoordinate x2,TCoordinate y2);
void drawCircle(TCoordinate x,TCoordinate y,TCoordinate r);
void fillCircle(TCoordinate x,TCoordinate y,TCoordinate r);
void drawEllipse(TCoordinate x,TCoordinate y,TCoordinate r_x,TCoordinate r_y);
void fillEllipse(TCoordinate x,TCoordinate y,TCoordinate r_x,TCoordinate r_y);
void drawPolygon(polygon<int> const &poly);
void fillPolygon(polygon<int> const &poly);
// bitmap output
void putSurface(TCoordinate x,TCoordinate y,wSurface const &pic);
// function for text output
int cursorX() const
{ return CursorX; }
int cursorY() const
{ return CursorY; }
void gotoXY(TCoordinate x,TCoordinate y);
void putChar(TCoordinate x,TCoordinate y, unsigned char c,wFont &font);
void print(string const &text, wFont &font);
void printLn(string const &text, wFont &font);
void setTextAlignment(TTextAlignment align) {
TextAlignment = align;
}
static void makePixelFormat(SDL_PixelFormat &fmt,TSize bitdepth,TSize channels = 3,
TColor colorkey = 0,float surfalpha = 0,SDL_Palette *pal = NULL);
private:
void killSurface();
void putSurface(int const x, int const y, SDL_Rect &srcrect, wSurface &pic);
void copyDataBlock(wSurface const &src);
void copyTransformedSurface(wSurface const &src,wAffineTransformation const &trans);
static void stretchSurface(SDL_Surface *dest,SDL_Surface *src,double stretchx = 1,double stretchy = 1);
static void transformSurface(SDL_Surface *dest,SDL_Surface *src,wAffineTransformation const &trans,TColor back_color = 0);
SDL_Surface *createSameFormatSurface(TSize width,TSize height) const;
};
class wScreenSurface: public wSurface {
public:
wScreenSurface(TSize width,TSize height,Uint32 flags,TSize bpp = 0);
void updateRect(TCoordinate x,TCoordinate y,TCoordinate w,TCoordinate h) {
SDL_UpdateRect(Surface,x,y,w,h);
}
void flip() const {
SDL_Flip(Surface);
}
void setCaption(string const &caption) {
SDL_WM_SetCaption(caption.c_str(),NULL);
}
};
// wFont ----------------------------------------------------------------------
class wFont {
public:
struct wGlyph {
bool Present;
int BaseX;
int BaseY;
unsigned Width;
SDL_Rect Boundary;
};
TSize static const MaxCharacterCount = 256;
string Name;
// it is implied that the base line is at 0
int TopLine;
int BottomLine;
wGlyph CharTable[MaxCharacterCount];
auto_ptr<wSurface> Surface;
wFont();
rectangle<wSurface::TCoordinate> getExtent(string const &s) const;
void load(xml_file::tag &cfgtag, istream &datastrm);
void save(xml_file::tag &cfgtag, ostream &datastrm);
wFont *convert(SDL_PixelFormat &fmt,Uint32 flags) const;
wFont *convertToDisplay() const;
wFont *convertForAcceleratedBlit() const;
private:
void copyDataBlock(wFont const &src);
};
#endif
-------------- next part --------------
// ----------------------------------------------------------------------------
// Description : SDL audio wrappers
// ----------------------------------------------------------------------------
// Remarks : wAudioStream::mixTo is called within the audio thread.
// Things requiring I/O and similar things had better go into
// wAudioStream::tick(). Its execution is automatically protected by
// the audio lock.
//
// ----------------------------------------------------------------------------
// © Copyright 2000 by Team WAM
// ----------------------------------------------------------------------------
#ifndef WAM_SDL_AUDIO
#define WAM_SDL_AUDIO
#include
#include
#include
#include <ixlib_array.hh>
#include <ixlib_garbage.hh>
#include <ixlib_string.hh>
#include <ixlib_ring_queue.hh>
#include “output/sdl_base.hh”
typedef TSize wAudioFrequency;
typedef Uint16 wAudioLayout;
typedef Sint32 wSampleValue;
#define SDLAUDIO_MIXBITS 28
#define SDLAUDIO_SV_MAXIMUM (1 << SDLAUDIO_MIXBITS - 1)
#define SDLAUDIO_REPEAT_INF -1u
namespace wAudio {
void mix(wSampleValue *dest,void *srcstart,void *srcend,TSize destsamples,
wAudioLayout srclayout,TSize srcchannels = 1,TSize destchannels = 1,
float lvolume = 1,float rvolume = 1,float speed = 1,
void **srcpos = NULL,TSize *destcount = NULL);
void panning2volumes(float vol,float pan,float &lvol,float &rvol);
void volumes2panning(float lvol,float rvol,float &vol,float &pan);
}
struct wAudioFormat {
wAudioFrequency Frequency;
TSize Channels;
wAudioLayout Layout;
wAudioFormat(TSize freq = 22050,TSize channels = 2,wAudioLayout layout = AUDIO_S16);
void set(TSize freq = 22050,TSize channels = 2,wAudioLayout layout = AUDIO_S16);
void getFromSpec(SDL_AudioSpec const &spec);
void fillSpec(SDL_AudioSpec &spec) const;
TSize getBytesPerSampleValue() const;
TSize getBytesPerSample() const;
};
class wAudioData {
auto_array Data;
wAudioFormat Format;
TSize Size; // samples
TSize UseCount;
public:
wAudioData();
TSize getSampleCount() const {
return Size;
}
wAudioFormat const &getFormat() const {
return Format;
}
TByte const *get() const {
return Data.get();
}
wAudioData *convertTo(wAudioFormat const &fmt);
void loadWAV(istream &istr);
TSize getByteSize() const {
return Size * Format.getBytesPerSample();
}
float getDuration() const {
return Size / (float) Format.Frequency;
}
};
class wAudioStream;
class wAudioManager {
protected:
public:
typedef unsigned wStreamId;
struct wStreamInfo {
wStreamId Id;
ref Stream;
};
struct wNotificationHandler {
enum wNotificationType { STARTED,ENDED,REMOVED };
virtual ~wNotificationHandler() {
}
virtual void operator()(wNotificationType type,wStreamId id) = 0;
};
protected:
// mandatory-lock data
typedef vector wStreamList;
wStreamList Streams;
wStreamId NextId;
// only accessed in callback
auto_array<wSampleValue> MixBuffer;
auto_array<TByte> ConvertedMixBuffer;
TSize CallbackCalls;
// read-only
TSize BufferSize; // samples
SDL_AudioSpec InternalPlayFormat;
wAudioFormat PlayFormat;
typedef vector<wNotificationHandler *> wNotificationHandlerList;
wNotificationHandlerList NotificationHandlerList;
public:
typedef wStreamList::iterator iterator;
typedef wStreamList::const_iterator const_iterator;
wAudioManager(TSize freq = 22050,TSize channels = 2,wAudioLayout layout = AUDIO_S16,
TSize buffer = 1024);
~wAudioManager();
iterator begin() {
return Streams.begin();
}
const_iterator begin() const {
return Streams.begin();
}
iterator end() {
return Streams.end();
}
const_iterator end() const {
return Streams.end();
}
TSize size() const {
return Streams.size();
}
TSize countCallbacks() const {
return CallbackCalls;
}
wAudioFormat const &getPlayFormat() const;
// advisory: how many samples one mixTo will maximally request
TSize getMaxRequestLength() const;
ref<wAudioStream> getStream(wStreamId id) const;
wStreamId addStream(ref<wAudioStream> strm);
void removeStream(wStreamId id);
bool isStreamActive(wStreamId id) const;
void addNotificationHandler(wNotificationHandler *handler);
void removeNotificationHandler(wNotificationHandler *handler);
void tick();
void pause();
void play();
// private:
void callback(void *stream,TSize len);
private:
void notify(wNotificationHandler::wNotificationType type,wStreamId id) const;
void cleanStreams();
wStreamList::iterator getStreamIterator(wStreamId id);
wStreamList::const_iterator getStreamIterator(wStreamId id) const;
};
class wAudioStream {
protected:
wAudioManager *Manager;
float LVolume,RVolume;
public:
wAudioStream(float vol = 1,float panning = 0);
virtual ~wAudioStream() {
}
virtual string describe() = 0;
void setVolume(float vol = 1,float panning = 0);
float getVolume() const;
float getPanning() const;
protected:
virtual void startUp(wAudioManager *mgr);
virtual void tick() = 0;
virtual void mixTo(wSampleValue *data,TSize samples,TSize frequency,TSize channels) = 0;
virtual bool isDone() const = 0;
friend class wAudioManager;
};
class wAudioTestStream : public wAudioStream {
private:
typedef wAudioStream Super;
float Angle;
float SineFrequency;
public:
wAudioTestStream(float sinefreq = 440,float vol = 1,float panning = 0);
string describe();
void tick();
void mixTo(wSampleValue *data,TSize samples,TSize frequency,TSize channels);
bool isDone() const {
return false;
}
};
class wAudioDataStream : public wAudioStream {
typedef wAudioStream Super;
wAudioData &Data;
TByte const *Position;
TSize RepeatCount;
float Delay;
TSize DelaySamples;
wAudioFormat const &Format;
public:
wAudioDataStream(wAudioData &data,TSize repeatcount = 1,float delay = 0,float vol = 1,float panning = 0);
string describe();
void startUp(wAudioManager *mgr);
void tick();
void mixTo(wSampleValue *data,TSize samples,TSize frequency,TSize channels);
bool isDone() const;
wAudioData const &getData() const {
return Data;
}
};
class wAudioBufferedStream : public wAudioStream {
private:
typedef wAudioStream Super;
float Speed;
ring_queue SoundBuffer;
wAudioFormat Format;
TSize BytesPerSample;
public:
wAudioBufferedStream(float vol = 1,float panning = 0);
void startUp(wAudioManager *mgr);
void tick();
void mixTo(wSampleValue *data,TSize samples,TSize frequency,TSize channels);
bool isDone() const;
protected:
virtual void internalStartUp(wAudioManager *mgr,wAudioFormat &fmt) = 0;
virtual bool isEndOfStream() const = 0;
virtual TSize getStreamData(void *data,TSize maxsize) = 0;
};
#endif