////////////////////////////////////////////////////////////////////////////// // // This file is part of the Atari Machine Specific Library, // and is Copyright 1992 by Warwick W. Allison. // // You are free to copy and modify these sources, provided you acknoledge // the origin by retaining this notice, and adhere to the conditions // described in the file COPYING. // ////////////////////////////////////////////////////////////////////////////// #ifndef _Sprite_h #define _Sprite_h ////////////////////////////////////////////////////////////////////////////// // // Sprites // ------- // // Small objects, double buffered. // // Sprites have position (x,y), and shape (an index into a list of // Incarnations). They can be drawn, wiped, moved and reshaped. // // Incarnations are positionless images that can be drawn and wiped. // They come in many forms, each tuned to give certain qualities: // // class Incarnation // Base class from which others are derived. // // class MonochromeIncarnation // 16 pixels wide (any height), monochrome image (For STHigh and TTHigh). // // class PreshiftedMonochromeIncarnation // 16 pixels wide, Faster than regular images, but use 32x memory. // // class WideMonochromeIncarnation // 32 pixels wide, monochrome image. // // class ColourIncarnation // 16 pixels wide, 16 colour (for STLow and TTMedium). // // class PreshiftedColourIncarnation // 16 pixels wide, Faster than regular colour sprites. // // class WideColourIncarnation // 32 pixels wide. // ////////////////////////////////////////////////////////////////////////////// #include #include #include "DoubleBuffer.h" class Incarnation { public: // Set hot spot (default (0,0)) void SetHotSpot(short x, short y); // I/O virtual int fput(FILE *fp); // Draw/Wipe image from double buffer page. Coordinates are in pixels. virtual void Draw(short x, short y, long *Store)=0; virtual int TouchDraw(short x, short y, long *Store)=0; // not implemented virtual void Wipe(long *Store)=0; // Take the area at (x,y) on the given screen as the image. // x must be multiple of 16. virtual void GetImage(Screen&, int x, int y)=0; // Return width and height of the incarnation. // Width is actual pixel width from the left. short Width() { return width; } short Height() { return height; } // Words of backing store used by the incarnmation (used by Sprite) int BackingRequired() { return Backing; } protected: Incarnation(FILE *fp); Incarnation(short h, int b); short width,height; // In pixels short HotX=0,HotY=0; int Backing; }; class Sprite { public: // Constructors: // A sprite with one shape. Sprite(Incarnation *OnlyOne); // A sprite with an array of shapes. Sprite(Incarnation **ListOfThem,int Count); // A sprite with a list of (undefined) shapes. Sprite(short maxinca); // A sprite with the same shapes as another sprite. Sprite(Sprite& Copy); // A sprite from a file. Sprite(const char *filename); Sprite(FILE *); // Destructor ~Sprite(); // I/O int Load(const char *filename); int Save(const char *filename); int fput(FILE *); int fget(FILE *); // Draw on current page void Draw(); int TouchDraw(); // not implemented // Remove from page. If already wiped, does nothing. void Wipe(); // Choose incarnation, starting from 0. void ShapeTo(short); // Scale of pixels to coords. Coord = 2**Scale * Pixel // All values below are scaled by this amount void Scale(short s) { Shift=s; } // Move void MoveTo(int x, int y); void MoveBy(int x, int y); // Set one of the possible shapes to a given Incarnation void SetImage(int i, Incarnation* In); // Inspectors int X() { return x; } int Y() { return y; } int Shape() { return shape; } int Width() { return Inca[shape]->Width() << Shift; } int Height() { return Inca[shape]->Height() << Shift; } protected: int x,y; short shape; short Shift=0; long *BackingStore[2]; unsigned int BackingSize; char *OverlayMask; short MaxInca; Incarnation **Inca; // Dynamically allocated array of *Incarnation private: bool ExternalInca; }; // // Mobile Sprite - an experimental derived class of Sprite. // enum BoundaryEffect {Bounce, Wrap, Stop, Watch}; const int HitNorth=1; const int HitSouth=2; const int HitEast=4; const int HitWest=8; class MobileSprite : public Sprite { public: MobileSprite(Incarnation **Them,int Count) : Sprite(Them,Count) {} MobileSprite(Incarnation *OnlyOne) : Sprite(OnlyOne) {} MobileSprite(short maxinca) : Sprite(maxinca) {} MobileSprite(const char *filename) : Sprite(filename) {} void Accelerate(int, int); bool Stationary() { return (!xi && !yi); } void Speed(int, int); void XSpeed(int); void YSpeed(int); int XSpeed(); int YSpeed(); void Range(int, int, int, int); short Move(); // Efftected Edges returned void Unmove(); // Just undo the move void Rebound(short Walls); // Undo and rebound against given walls void Frictate(short fric); void AtBoundary(BoundaryEffect, short Bouncy=256); void AtBoundary(BoundaryEffect North, BoundaryEffect South, BoundaryEffect East, BoundaryEffect West, short Bouncy=256); private: int xi=0,yi=0; int Bounciness=256; int MinX= -10000; int MinY= -10000; int MaxX= +10000; int MaxY= +10000; BoundaryEffect AtEdge[4]={Watch,Watch,Watch,Watch}; }; ///////////////////////////// // // Below are all the derived Incarnations, // see main comment for details. // ///////////////////////////// class MonochromeIncarnation : public Incarnation { public: MonochromeIncarnation(int height); virtual ~MonochromeIncarnation(); virtual void Draw(short x, short y, long *Store); virtual int TouchDraw(short x, short y, long* Store); virtual void Wipe(long *Store); virtual int fput(FILE *fp); virtual void GetImage(Screen&, int x, int y); private: friend Incarnation* IncarnationReader(FILE *fp); MonochromeIncarnation(FILE*); short unsigned *Data,*Mask; }; class WideMonochromeIncarnation : public Incarnation { public: WideMonochromeIncarnation(int height); virtual ~WideMonochromeIncarnation(); virtual void Draw(short x, short y, long *Store); virtual int TouchDraw(short x, short y, long* Store); virtual void Wipe(long *Store); virtual int fput(FILE *fp); virtual void GetImage(Screen&, int x, int y); private: friend Incarnation* IncarnationReader(FILE *fp); WideMonochromeIncarnation(FILE*); unsigned long *Data,*Mask; }; class PreshiftedMonochromeIncarnation : public Incarnation { public: PreshiftedMonochromeIncarnation(int height); virtual ~PreshiftedMonochromeIncarnation(); virtual void Draw(short x, short y, long *Store); virtual int TouchDraw(short x, short y, long* Store); virtual void Wipe(long *Store); virtual int fput(FILE *fp); virtual void GetImage(Screen&, int x, int y); private: friend Incarnation* IncarnationReader(FILE *fp); PreshiftedMonochromeIncarnation(FILE*); unsigned long *Data[16],*Mask[16]; }; class WideColourIncarnation : public Incarnation { public: WideColourIncarnation(int height); virtual ~WideColourIncarnation(); virtual void Draw(short x, short y, long *Store); virtual int TouchDraw(short x, short y, long* Store); virtual void Wipe(long *Store); virtual int fput(FILE *fp); virtual void GetImage(Screen&, int x, int y); private: friend Incarnation* IncarnationReader(FILE *fp); WideColourIncarnation(FILE*); long unsigned *Data,*Mask; }; class ColourIncarnation : public Incarnation { public: ColourIncarnation(int height); virtual ~ColourIncarnation(); virtual void Draw(short x, short y, long *Store); virtual int TouchDraw(short x, short y, long* Store); virtual void Wipe(long *Store); virtual int fput(FILE *fp); virtual void GetImage(Screen&, int x, int y); private: friend Incarnation* IncarnationReader(FILE *fp); ColourIncarnation(FILE*); short unsigned *Data,*Mask; }; class PreshiftedColourIncarnation : public Incarnation { public: PreshiftedColourIncarnation(int height); virtual ~PreshiftedColourIncarnation(); virtual void Draw(short x, short y, long *Store); virtual int TouchDraw(short x, short y, long* Store); virtual void Wipe(long *Store); virtual int fput(FILE *fp); virtual void GetImage(Screen&, int x, int y); private: friend Incarnation* IncarnationReader(FILE *fp); PreshiftedColourIncarnation(FILE*); short unsigned *Data[16],*Mask[16]; }; // Some inlines for efficiency... inline void Sprite::MoveTo(int X, int Y) { x=X; y=Y; } inline void Sprite::MoveBy(int X, int Y) { x+=X; y+=Y; } inline void Sprite::ShapeTo(short s) { shape=s; } inline void MobileSprite::Range(int minx, int miny, int maxx, int maxy) { MinX=minx; MaxX=maxx; MinY=miny; MaxY=maxy; } inline void MobileSprite::Speed(int x, int y) { xi=x; yi=y; } inline void MobileSprite::XSpeed(int x) { xi=x; } inline void MobileSprite::YSpeed(int y) { yi=y; } inline int MobileSprite::XSpeed() { return xi; } inline int MobileSprite::YSpeed() { return yi; } inline void MobileSprite::Accelerate(int x, int y) { xi+=x; yi+=y; } inline void MobileSprite::Unmove() { MoveBy(-xi,-yi); } inline void MobileSprite::Frictate(short f) { f=256-f; xi=xi*f/256; yi=yi*f/256; } #endif // !Sprite_h