//====================================================================== // TYPES //====================================================================== #include "SDL_image.h" #include "px/cache.hh" namespace { class SurfaceAlloc_Alpha { public: Surface *acquire(const std::string &name) { return enigma::LoadImage(name.c_str()); } void release(Surface *s) { delete s; } }; class SurfaceAlloc { public: Surface * acquire(const std::string &name) { string fname = enigma::FindDataFile(string("gfx/") + name+".png"); SDL_Surface *s = IMG_Load(fname.c_str()); if (s) { SDL_Surface *img = 0; if (options::BitsPerPixel == 8) { SDL_SetColorKey(s, SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(s->format, 255,0,255)); img = SDL_DisplayFormat(s); } else { if (s->flags & SDL_SRCALPHA) { img = SDL_DisplayFormatAlpha(s); } else { SDL_SetColorKey(s, SDL_SRCCOLORKEY|SDL_RLEACCEL, SDL_MapRGB(s->format, 255,0,255)); img = SDL_DisplayFormat(s); } } if (img) { SDL_FreeSurface(s); return new Surface(img); } return new Surface(s); } return 0; // Surface *s = enigma::LoadImage(name.c_str()); // if (s->get_surface()->flags & SDL_SRCALPHA) // cout << "alpha: " < SurfaceCache; typedef cache::Cache SurfaceCache_Alpha; } //---------------------------------------- // Image //---------------------------------------- namespace { class Image { public: // Constructors. Image(px::Surface *i) : image(i), rect(), refcount(1) { rect.w = i->width(); rect.h = i->height(); } Image(px::Surface *i, px::Rect r) : image(i), rect(r), refcount(1) {} // Destructor. ~Image() { // `image' need not be deleted; this is handled in the // global image cache. } // Functions. void incref() { ++refcount; } void decref() {if (--refcount == 0) delete this;} void draw(px::GC &gc, int x, int y) { blit(gc, x, y, image, rect); } // Variables. px::Surface *image; px::Rect rect; // location of image inside surface int refcount; }; } //---------------------------------------------------------------------- // MODELS //---------------------------------------------------------------------- namespace { class Model2d : public Model { public: virtual void draw(px::GC &gc, int x, int y) = 0; virtual void draw_shade(px::GC &gc, int x, int y) = 0; virtual void activate(double worldx, double worldy, bool is_sprite) {} virtual void deactivate() {} virtual bool is_garbage() const { return false; } virtual void tick(double dtime) {} virtual bool has_changed(Rect &changed_region) { return false; } // virtual Surface *get_image() = 0; // virtual Surface *get_shade() = 0; virtual Model2d *clone()=0; }; } //---------------------------------------- // ImageModel //---------------------------------------- namespace { class ImageModel : public Model2d { Image* image; int xoff, yoff; // relative origin of the image public: ImageModel(Image *i, int xo, int yo) : image(i), xoff(xo), yoff(yo) { image->incref(); } ImageModel(Surface *s, int xo, int yo) : image(new Image(s)), xoff(xo), yoff(yo) {} ImageModel(Surface *s, const Rect &r, int xo, int yo) : image(new Image(s, r)), xoff(xo), yoff(yo) {} ~ImageModel() {image->decref();} void draw(px::GC &gc, int x, int y) { assert(image); image->draw(gc, x+xoff, y+yoff); } void draw_shade(px::GC &gc, int x, int y) {} Model2d *clone() {return new ImageModel(image, xoff, yoff);} }; } //---------------------------------------- // ShadedModel //---------------------------------------- namespace { class ShadedModel : public Model2d { public: ShadedModel(Model2d *m, Model2d *sh) {model=m; shade=sh;} ~ShadedModel() { delete model; delete shade; } // Model2d interface void activate(double worldx, double worldy, bool is_sprite) { model->activate(worldx, worldy, is_sprite); } void deactivate() { model->deactivate(); } void set_callback(ModelCallback *cb) { model->set_callback(cb); } void reverse() { model->reverse(); } void draw(px::GC &gc, int x, int y) { if(model) model->draw(gc,x,y); } void draw_shade(px::GC &gc, int x, int y) { if(shade) shade->draw(gc,x,y); } Model2d *clone() { return new ShadedModel(model->clone(), shade->clone()); } private: Model2d *model, *shade; }; } //---------------------------------------------------------------------- // CompositeModel // // This kind of model consists of two layers: one background layer and // some foreground layer that is drawn over the background. Both // layers may be animated. This model make it easy to compose complex // animations from simple ones; see models-2d.lua for a few examples. //---------------------------------------------------------------------- namespace { class CompositeModel : public Model2d { Model2d *bg, *fg; public: CompositeModel(Model2d *b, Model2d *f) : bg(b), fg(f) {} ~CompositeModel() { delete bg; delete fg; } // Animation interface void set_callback(ModelCallback *cb) { bg->set_callback(cb); fg->set_callback(cb); } double duration() const { return 0; } void reverse() { bg->reverse(); fg->reverse(); } // Model2d interface void activate(double worldx, double worldy, bool is_sprite) { bg->activate(worldx, worldy, is_sprite); fg->activate(worldx, worldy, is_sprite); } void deactivate() { bg->deactivate(); fg->deactivate(); } void draw(px::GC &gc, int x, int y) { bg->draw(gc,x,y); fg->draw(gc,x,y); } void draw_shade(px::GC &gc, int x, int y) { bg->draw_shade(gc,x,y); } Model2d *clone() { return new CompositeModel(bg->clone(), fg->clone()); } }; } //---------------------------------------- // RandomModel //---------------------------------------- namespace { class RandomModel : public Model2d { vector modelnames; public: void draw(px::GC &gc, int x, int y) {} void draw_shade(px::GC &gc, int x, int y) {} void add_model(const string &name) {modelnames.push_back(name);} // Model2d interface Model2d *clone(); }; } //---------------------------------------- // Alias //---------------------------------------- namespace { class AliasModel : public Model2d { string name; public: AliasModel(const string &modelname) : name(modelname) {} void draw(px::GC &gc, int x, int y) {} void draw_shade(px::GC &gc, int x, int y) {} Model2d *clone(); }; } //---------------------------------------- // Animation //---------------------------------------- namespace { class AnimFrame : public px::Nocopy { public: AnimFrame(Model2d *m, double dur) : model(m), duration(dur) {} ~AnimFrame() { delete model; } Model2d *model; double duration; }; class AnimRep { public: AnimRep(bool l) : loop(l), refcount(1) {} ~AnimRep() { delete_sequence(frames.begin(), frames.end()); } double duration() const { double d = 0; for (unsigned i=0; iduration; return d; } vector frames; bool loop; int refcount; }; class Anim2d : public Model2d, public px::Nocopy { public: Anim2d(bool loop) : rep(new AnimRep(loop)) {} ~Anim2d(); double duration() const; void set_callback(ModelCallback *cb) { callback = cb; } void add_frame(Model2d *m, double duration); // Model2d interface void draw(px::GC &gc, int x, int y); void draw_shade(px::GC &gc, int x, int y); Model2d *clone() { return new Anim2d(rep); } void reverse() { reversep = !reversep; } void activate(double worldx, double worldy, bool is_sprite); void deactivate(); void tick(double dtime); bool has_changed(Rect &changed_region); bool is_garbage() const { return finishedp; } private: Anim2d(AnimRep *r); AnimRep *rep; unsigned curframe; // Current frame number. double frametime; // Elapsed time since frame was activated bool finishedp; // Animation has finished bool changedp; // Model state has changed since last redraw bool reversep; // Play the animation in reverse direction double posx, posy; // World coordinates of the sprite bool is_sprite; // False if item/stone animation ModelCallback *callback; }; } namespace { struct Field { static const int NUM_LAYERS = 3; Field() { fill_n(layers, NUM_LAYERS, (Model2d*)0); redrawp = updatep = false; } ~Field() { delete_sequence(layers, layers+NUM_LAYERS); } Model2d* layers[NUM_LAYERS]; bool redrawp; bool updatep; }; class Sprite : public Nocopy { public: Model2d *model; V3 pos; SpriteLayer layer; bool visible; Sprite(const V3 & p, SpriteLayer l, Model2d *m) : model(m), pos(p), layer(l) {} ~Sprite() { delete model; } }; typedef Array2 FieldArray; typedef list ModelList; //typedef map SpriteList; typedef vector SpriteList; } namespace { class TextDisplay { public: TextDisplay(Rect a, Font &f); void set_text(const string &t, TextMode m); void deactivate() { active = false; } bool is_active() const { return active; } void tick(double dtime); bool has_changed() { return changedp; } void draw(px::GC &gc, const Rect &r); private: string text; bool active, changedp; TextMode mode; Rect area; double xoff; const double scrollspeed; // pixels per second std::auto_ptr textsurface; px::Font &font; double time, maxtime; }; }