X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=lib%2Fspecial%2Fsprite.cpp;h=d713d5fd2a3643cbe5fa5d218d7b45faf7bf23b3;hb=d1358d551f2415de1495c9f55916787721f42f82;hp=75e6e5459f23f69dcbd26b4c1af885fddd9633e8;hpb=4b476ec30e7dd62249328054402d6493c20a685d;p=supertux.git diff --git a/lib/special/sprite.cpp b/lib/special/sprite.cpp index 75e6e5459..d713d5fd2 100644 --- a/lib/special/sprite.cpp +++ b/lib/special/sprite.cpp @@ -29,103 +29,277 @@ using namespace SuperTux; Sprite::Sprite(lisp_object_t* cur) { - init_defaults(); + for(; !lisp_nil_p(cur); cur = lisp_cdr(cur)) + { + std::string token = lisp_symbol(lisp_car(lisp_car(cur))); + lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur))); + LispReader reader(lisp_cdr(lisp_car(cur))); + + if(token == "name") + name = lisp_string(data); + else if(token == "action") + parse_action(reader); + else + std::cerr << "Warning: Unknown sprite field: " << token << std::endl; + } - LispReader reader(cur); + if(name.empty()) + Termination::abort("Error: Sprite wihtout name.", ""); + if(actions.empty()) + Termination::abort("Error: Sprite wihtout actions.", ""); +} - if(!reader.read_string("name", name)) - st_abort("Sprite wihtout name", ""); - reader.read_int("x-hotspot", x_hotspot); - reader.read_int("y-hotspot", y_hotspot); - reader.read_float("fps", fps); +Sprite::~Sprite() +{ + for(Actions::iterator i_act = actions.begin(); i_act != actions.end(); ++i_act) + { + for(std::vector::iterator i_sur = i_act->second->surfaces.begin(); + i_sur != i_act->second->surfaces.end(); ++i_sur) + { + if(!i_act->second->mirror) + delete *i_sur; + } + delete i_act->second; + } +} - std::vector images; - if(!reader.read_string_vector("images", images)) - st_abort("Sprite contains no images: ", name.c_str()); +void +Sprite::parse_action(LispReader& lispreader) +{ + action = new Action; + + init_defaults(action); + + if(!lispreader.read_string("name", action->name)) + if(!actions.empty()) + Termination::abort("Error: If there are more than one action, they need names!", ""); + lispreader.read_int("x-offset", action->x_offset); + lispreader.read_int("y-offset", action->y_offset); + lispreader.read_int("z-order", action->z_order); + lispreader.read_float("fps", action->fps); + + /* TODO: add a top filter entry */ + std::vector mask_color; + lispreader.read_int_vector("apply-mask", mask_color); + if(mask_color.size() == 4) + { + for(std::vector::iterator i = action->surfaces.begin(); + i < action->surfaces.end(); i++) + { + (*i)->apply_mask(Color(mask_color)); + } + } + + action->mirror = false; + std::string mirror_action; + lispreader.read_string("mirror-action", mirror_action); + if(!mirror_action.empty()) + { + action->mirror = true; + Action* act_tmp = get_action(mirror_action); + if(act_tmp == NULL) + std::cerr << "Warning: Could not mirror action. Action not found\n" + "Mirror actions must be defined after the real one!\n"; + else + action->surfaces = act_tmp->surfaces; + } - for(std::vector::size_type i = 0; i < images.size(); ++i) + // Load images + if(!action->mirror) { - surfaces.push_back( + std::vector images; + if(!lispreader.read_string_vector("images", images)) + Termination::abort("Sprite contains no images: ", action->name); + + for(std::vector::size_type i = 0; i < images.size(); i++) + { + action->surfaces.push_back( new Surface(datadir + "/images/" + images[i], true)); - } + } + } + actions[action->name] = action; +} + +/*void Sprite::parse_filter(LispReader& lispreader) +{ + +}*/ + +void +Sprite::init_defaults(Action* act) +{ + act->x_offset = 0; + act->y_offset = 0; + act->z_order = 0; + act->fps = 10; - frame_delay = 1000.0f/fps; + start_animation(-1); } -Sprite::~Sprite() +void +Sprite::set_action(std::string act) +{ +if(!next_action.empty() && animation_loops > 0) + { + next_action = act; + return; + } +Actions::iterator i = actions.find(act); +if(i == actions.end()) + { + std::cerr << "Warning: Action '" << act << "' not found on Sprite '" << name << "'\n"; + return; + } +action = i->second; +} + +Sprite::Action* +Sprite::get_action(std::string act) { - for(std::vector::iterator i = surfaces.begin(); i != surfaces.end(); - ++i) - delete *i; +Actions::iterator i = actions.find(act); +if(i == actions.end()) + { + std::cerr << "Warning: Action '" << act << "' not found on Sprite '" << name << "'\n"; + return NULL; + } +return i->second; } void -Sprite::init_defaults() +Sprite::start_animation(int loops) { - x_hotspot = 0; - y_hotspot = 0; - fps = 10; - time = 0; - frame_delay = 1000.0f/fps; +reset(); +animation_loops = loops; } void -Sprite::update(float /*delta*/) +Sprite::reset() +{ +frame = 0; +last_tick = SDL_GetTicks(); +animation_reversed = false; +next_action.clear(); +} + +bool +Sprite::check_animation() { - //time += 10*delta; - //std::cout << "Delta: " << delta << std::endl; +return animation_loops; } void -Sprite::draw(DrawingContext& context, const Vector& pos, int layer, - Uint32 drawing_effect) +Sprite::reverse_animation(bool reverse) { - time = SDL_GetTicks(); - unsigned int frame = get_current_frame(); +animation_reversed = reverse; - if (frame < surfaces.size()) - { - Surface* surface = surfaces[frame]; - - context.draw_surface(surface, pos - Vector(x_hotspot, y_hotspot), layer, drawing_effect); - } +if(animation_reversed) + frame = get_frames()-1; +else + frame = 0; } -#if 0 void -Sprite::draw_part(float sx, float sy, float x, float y, float w, float h) +Sprite::update() { - time = SDL_GetTicks(); - unsigned int frame = get_current_frame(); +if(animation_loops == 0) + { + if(frame >= get_frames() || frame < 0) + frame = 0; + return; + } + +float frame_inc = (action->fps/1000.0) * (SDL_GetTicks() - last_tick); +last_tick = SDL_GetTicks(); - if (frame < surfaces.size()) - surfaces[frame]->draw_part(sx, sy, x - x_hotspot, y - y_hotspot, w, h); +if(animation_reversed) + frame -= frame_inc; +else + frame += frame_inc; + +if(animation_reversed) + { + if(frame < 0 || frame >= (float)get_frames()) + { // last case can happen when not used reverse_animation() + float excedent = frame - 0; + frame = get_frames() - 1; + if(animation_loops > 0) + { + animation_loops--; + if(animation_loops == 0 && !next_action.empty()) + { + set_action(next_action); + start_animation(-1); + } + } + + if(fabsf(excedent) < get_frames()) + frame += excedent; + } + } +else + { + if(frame >= (float)get_frames()) + { + float excedent = frame - get_frames(); + frame = 0; + if(animation_loops > 0) + { + animation_loops--; + if(animation_loops == 0 && !next_action.empty()) + { + set_action(next_action); + start_animation(-1); + } + } + + if(excedent < get_frames()) + frame += excedent; + } + } } -#endif void -Sprite::reset() +Sprite::draw(DrawingContext& context, const Vector& pos, int layer, + Uint32 drawing_effect) { - time = 0; + update(); + + if((int)frame >= get_frames() || (int)frame < 0) + std::cerr << "Warning: frame out of range: " << (int)frame + << "/" << get_frames() << " at " << get_name() + << "/" << get_action_name() << std::endl; + else + context.draw_surface(action->surfaces[(int)frame], + pos - Vector(action->x_offset, action->y_offset), layer + action->z_order, + drawing_effect); } -int -Sprite::get_current_frame() const +void +Sprite::draw_part(DrawingContext& context, const Vector& source, const Vector& size, + const Vector& pos, int layer, Uint32 drawing_effect) { - unsigned int frame = static_cast(fmodf(time, surfaces.size()*frame_delay)/frame_delay); - return frame % surfaces.size(); + update(); + + if((int)frame >= get_frames() || (int)frame < 0) + std::cerr << "Warning: frame out of range: " << (int)frame + << "/" << get_frames() << " at sprite: " << get_name() + << "/" << get_action_name() << std::endl; + else + context.draw_surface_part(action->surfaces[(int)frame], source, size, + pos - Vector(action->x_offset, action->y_offset), layer + action->z_order, + drawing_effect); } int -Sprite::get_width() const +Sprite::get_width() { - return surfaces[get_current_frame()]->w; + return action->surfaces[get_frame()]->w; } int -Sprite::get_height() const +Sprite::get_height() { - return surfaces[get_current_frame()]->h; + return action->surfaces[get_frame()]->h; } /* EOF */