Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F125855
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
17 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/util/gui/animation.cpp b/util/gui/animation.cpp
index 68c6aa1f..04fd06f1 100644
--- a/util/gui/animation.cpp
+++ b/util/gui/animation.cpp
@@ -1,413 +1,432 @@
#include "animation.h"
#include <vector>
#include <math.h>
#include <sstream>
#include "util/token.h"
#include "util/trans-bitmap.h"
#include "util/bitmap.h"
#include "globals.h"
#include "../debug.h"
#include "../funcs.h"
#include "../file-system.h"
using namespace std;
using namespace Gui;
// Temporary solution
static void renderSprite(const Graphics::Bitmap & bmp, const int x, const int y, const int alpha, const bool hflip, const bool vflip, const Graphics::Bitmap & work){
if (alpha != 255){
Graphics::Bitmap::transBlender( 0, 0, 0, alpha );
if (hflip && !vflip){
bmp.translucent().drawHFlip(x,y, work);
} else if (!hflip && vflip){
bmp.translucent().drawVFlip(x,y, work);
} else if (hflip && vflip){
bmp.translucent().drawHVFlip(x,y, work);
} else if (!hflip && !vflip){
bmp.translucent().draw(x,y, work);
}
} else {
if (hflip && !vflip){
bmp.drawHFlip(x,y, work);
} else if (!hflip && vflip){
bmp.drawVFlip(x,y, work);
} else if (hflip && vflip){
bmp.drawHVFlip(x,y, work);
} else if (!hflip && !vflip){
bmp.draw(x,y, work);
}
}
}
Frame::Frame(const Token *the_token, imageMap &images) throw (LoadException):
bmp(0),
time(0),
horizontalFlip(false),
verticalFlip(false),
alpha(255){
if ( *the_token != "frame" ){
throw LoadException(__FILE__, __LINE__, "Not an frame");
}
const Token & tok = *the_token;
/* The usual setup of an animation frame is
// use image -1 to not draw anything, it can be used to get a blinking effect
(frame (image NUM) (alpha NUM) (offset x y) (hflip 0|1) (vflip 0|1) (time NUM))
*/
TokenView view = tok.view();
while (view.hasMore()){
try{
const Token * token;
view >> token;
if (*token == "image"){
// get the number
int num;
token->view() >> num;
// now assign the bitmap
bmp = images[num];
} else if (*token == "alpha"){
// get alpha
token->view() >> alpha;
} else if (*token == "offset"){
// Get the offset location it defaults to 0,0
double x=0, y=0;
try {
token->view() >> x >> y;
} catch (const TokenException & ex){
}
offset.set(x,y);
} else if (*token == "hflip"){
// horizontal flip
token->view() >> horizontalFlip;
} else if (*token == "vflip"){
// horizontal flip
token->view() >> verticalFlip;
} else if (*token == "time"){
// time to display
token->view() >> time;
} else {
Global::debug( 3 ) << "Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
token->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu animation parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
}
Frame::Frame(Graphics::Bitmap * bmp):
bmp(bmp),
time(0),
horizontalFlip(false),
verticalFlip(false),
alpha(255){
}
Frame::~Frame(){
}
void Frame::act(double xvel, double yvel){
scrollOffset.moveBy(xvel,yvel);
if (scrollOffset.getDistanceFromCenterX() >=bmp->getWidth()){
scrollOffset.setX(0);
} else if (scrollOffset.getDistanceFromCenterX() <= -(bmp->getWidth())){
scrollOffset.setX(0);
}
if (scrollOffset.getDistanceFromCenterY() >=bmp->getHeight()){
scrollOffset.setY(0);
} else if (scrollOffset.getDistanceFromCenterY() <= -(bmp->getHeight())){
scrollOffset.setY(0);
}
}
static bool closeFloat(double a, double b){
const double epsilon = 0.001;
return fabs(a-b) < epsilon;
}
void Frame::draw(const int xaxis, const int yaxis, const Graphics::Bitmap & work){
if (!bmp){
return;
}
if (!closeFloat(scrollOffset.getDistanceFromCenterX(), 0) || !closeFloat(scrollOffset.getDistanceFromCenterY(), 0)){
// Lets do some scrolling
// Graphics::Bitmap temp = Graphics::Bitmap::temporaryBitmap(bmp->getWidth(), bmp->getHeight());
//AnimationPoint loc;
AbsolutePoint loc;
if (scrollOffset.getRelativeX() < 0){
loc.setX(scrollOffset.getDistanceFromCenterX() + bmp->getWidth());
} else if (scrollOffset.getRelativeX() > 0){
loc.setX(scrollOffset.getDistanceFromCenterX() - bmp->getWidth());
}
if (scrollOffset.getRelativeY() < 0){
loc.setY(scrollOffset.getDistanceFromCenterY() + bmp->getHeight());
} else if (scrollOffset.getRelativeY() > 0){
loc.setY(scrollOffset.getDistanceFromCenterY() - bmp->getHeight());
}
/*
bmp->Blit((int) scrollOffset.getDistanceFromCenterX(), (int) scrollOffset.getDistanceFromCenterY(), temp);
bmp->Blit((int) scrollOffset.getDistanceFromCenterX(), (int) loc.getY(), temp);
bmp->Blit((int) loc.getX(), (int) scrollOffset.getDistanceFromCenterY(), temp);
bmp->Blit((int) loc.getX(), (int) loc.getY(), temp);
renderSprite(temp, (int)(xaxis+offset.getDistanceFromCenterX()), (int)(yaxis+offset.getDistanceFromCenterY()), alpha, horizontalFlip, verticalFlip, work);
*/
double x = xaxis+offset.getDistanceFromCenterX();
double y = yaxis+offset.getDistanceFromCenterY();
renderSprite(*bmp,
(int)(x + scrollOffset.getDistanceFromCenterX()),
(int)(y + scrollOffset.getDistanceFromCenterY()),
alpha, horizontalFlip, verticalFlip, work);
renderSprite(*bmp,
(int)(x + loc.getX()),
(int)(y + scrollOffset.getDistanceFromCenterY()),
alpha, horizontalFlip, verticalFlip, work);
renderSprite(*bmp,
(int)(x + scrollOffset.getDistanceFromCenterX()),
(int)(y + loc.getY()),
alpha, horizontalFlip, verticalFlip, work);
renderSprite(*bmp,
(int)(x + loc.getX()),
(int)(y + loc.getY()),
alpha, horizontalFlip, verticalFlip, work);
} else {
renderSprite(*bmp, (int)(xaxis+offset.getDistanceFromCenterX()), (int)(yaxis+offset.getDistanceFromCenterY()), alpha, horizontalFlip, verticalFlip, work);
}
}
Animation::Animation(const Token *the_token) throw (LoadException):
id(0),
depth(BackgroundBottom),
ticks(0),
currentFrame(0),
loop(0),
allowReset(true){
images[-1] = 0;
std::string basedir = "";
- if ( *the_token != "anim" ){
+ if ( *the_token != "anim" && *the_token != "animation" ){
throw LoadException(__FILE__, __LINE__, "Not an animation");
}
/* The usual setup of an animation is
The images must be listed prior to listing any frames, basedir can be used to set the directory where the images are located
loop will begin at the subsequent frame listed after loop
axis is the location in which the drawing must be placed
location *old* - used to render in background or foreground (0 == background [default]| 1 == foreground)
depth - used to render in background or foreground space (depth background bottom|middle|top) | (depth foreground bottom|midle|top)
reset - used to allow resetting of animation (0 == no | 1 == yes [default])
velocity - used to get a wrapping scroll effect while animating
window - area in which the item will be contained
(anim (id NUM)
(location NUM)
(depth background|foreground NUM)
(basedir LOCATION)
(image NUM FILE)
(velocity x y)
(axis x y)
(frame "Read comments above in constructor")
(loop)
(reset NUM)
(window x1 y1 x2 y2))
*/
const Token & tok = *the_token;
TokenView view = tok.view();
while (view.hasMore()){
try{
const Token * token;
view >> token;
if (*token == "id"){
// get the id
token->view() >> id;
} else if (*token == "location"){
// translate location to depth
int location = 0;
token->view() >> location;
if (location == 0){
depth = BackgroundBottom;
} else if (location == 1){
depth = ForegroundBottom;
}
} else if (*token == "depth"){
// get the depth
std::string name, level;
token->view() >> name >> level;
if (name == "background"){
if (level == "bottom"){
depth = BackgroundBottom;
} else if (level == "middle"){
depth = BackgroundMiddle;
} else if (level == "top"){
depth = BackgroundTop;
}
} else if (name == "foreground"){
if (level == "bottom"){
depth = ForegroundBottom;
} else if (level == "middle"){
depth = ForegroundMiddle;
} else if (level == "top"){
depth = ForegroundTop;
}
}
} else if (*token == "basedir"){
// set the base directory for loading images
token->view() >> basedir;
} else if (*token == "image"){
// add bitmaps by number to the map
int number;
std::string temp;
token->view() >> number >> temp;
Graphics::Bitmap *bmp = new Graphics::Bitmap(Storage::instance().find(Filesystem::RelativePath(basedir + temp)).path());
if (bmp->getError()){
delete bmp;
} else {
images[number] = bmp;
}
} else if (*token == "axis"){
// Get the axis location it defaults to 0,0
double x=0, y=0;
try {
token->view() >> x >> y;
} catch (const TokenException & ex){
}
axis.set(x,y);
} else if (*token == "window"){
// Windowed area where to clip if necessary otherwise it defaults to max
double x1=0,x2=0, y1=0,y2=0;
try {
token->view() >> x1 >> y1 >> x2 >> y2;
} catch (const TokenException & ex){
}
window.set(x1,y1,x2,y2);
} else if (*token == "velocity"){
// This allows the animation to get a wrapping scroll action going on
double x=0, y=0;
try {
token->view() >> x >> y;
} catch (const TokenException & ex){
}
velocity.set(x,y);
} else if (*token == "frame"){
// new frame
Frame *frame = new Frame(token, images);
frames.push_back(frame);
} else if (*token == "loop"){
// start loop here
int l;
token->view() >> l;
if (l >= (int)frames.size()){
ostringstream out;
out << "Loop location is larger than the number of frames. Loop: " << loop << " Frames: " << frames.size();
throw LoadException(__FILE__, __LINE__, out.str());
}
loop = l;
} else if (*token == "reset"){
// Allow reset of animation
token->view() >> allowReset;
} else {
Global::debug( 3 ) << "Unhandled menu attribute: "<<endl;
if (Global::getDebug() >= 3){
token->print(" ");
}
}
} catch ( const TokenException & ex ) {
throw LoadException(__FILE__, __LINE__, ex, "Menu animation parse error");
} catch ( const LoadException & ex ) {
throw ex;
}
}
}
Animation::Animation(const std::string & background) throw (LoadException):
id(0),
depth(BackgroundBottom),
ticks(0),
currentFrame(0),
loop(0),
allowReset(true){
// add bitmap
Graphics::Bitmap *bmp = new Graphics::Bitmap(Storage::instance().find(Filesystem::RelativePath(background)).path());
if (bmp->getError()){
delete bmp;
throw LoadException(__FILE__,__LINE__, "Problem loading file: " + background);
} else {
images[0] = bmp;
}
Frame *frame = new Frame(bmp);
frames.push_back(frame);
}
+Animation::Animation(const Filesystem::AbsolutePath & path) throw (LoadException):
+id(0),
+depth(BackgroundBottom),
+ticks(0),
+currentFrame(0),
+loop(0),
+allowReset(true){
+ // add bitmap
+ Graphics::Bitmap *bmp = new Graphics::Bitmap(path.path());
+ if (bmp->getError()){
+ delete bmp;
+ throw LoadException(__FILE__,__LINE__, "Problem loading file: " + path.path());
+ } else {
+ images[0] = bmp;
+ }
+ Frame *frame = new Frame(bmp);
+ frames.push_back(frame);
+}
+
Animation::Animation(Graphics::Bitmap * image):
id(0),
depth(BackgroundBottom),
ticks(0),
currentFrame(0),
loop(0),
allowReset(true){
images[0] = image;
Frame *frame = new Frame(image);
frames.push_back(frame);
}
Animation::~Animation(){
for (std::vector<Frame *>::iterator i = frames.begin(); i != frames.end(); ++i){
if (*i){
delete *i;
}
}
for (imageMap::iterator i = images.begin(); i != images.end(); ++i){
if (i->second){
delete i->second;
}
}
}
void Animation::act(){
// Used for scrolling
for (std::vector<Frame *>::iterator i = frames.begin(); i != frames.end(); ++i){
(*i)->act(velocity.getRelativeX(), velocity.getRelativeY());
}
if( frames[currentFrame]->time != -1 ){
ticks++;
if(ticks >= frames[currentFrame]->time){
ticks = 0;
forwardFrame();
}
}
}
void Animation::draw(const Graphics::Bitmap & work){
/* FIXME: should use sub-bitmaps here */
// Set clip from the axis default is 0,0,bitmap width, bitmap height
work.setClipRect(-(window.getPosition().getDistanceFromCenterX()),-(window.getPosition().getDistanceFromCenterY()),work.getWidth() - window.getPosition2().getDistanceFromCenterX(),work.getHeight() - window.getPosition2().getDistanceFromCenterY());
frames[currentFrame]->draw(axis.getDistanceFromCenterX(), axis.getDistanceFromCenterY(),work);
work.setClipRect(0,0,work.getWidth(),work.getHeight());
}
void Animation::forwardFrame(){
if (currentFrame < frames.size() -1){
currentFrame++;
} else {
currentFrame = loop;
}
}
void Animation::backFrame(){
if (currentFrame > loop){
currentFrame--;
} else {
currentFrame = frames.size() - 1;
}
}
diff --git a/util/gui/animation.h b/util/gui/animation.h
index dafedfd5..4e4a754c 100644
--- a/util/gui/animation.h
+++ b/util/gui/animation.h
@@ -1,78 +1,86 @@
#ifndef _paintown_gui_animation_h
#define _paintown_gui_animation_h
#include <vector>
#include <map>
#include "../load_exception.h"
#include "coordinate.h"
-class Token;
+class Filesystem;
+namespace Path{
+ class AbsolutePath;
+}
+typedef Path::AbsolutePath AbsolutePath;
+
namespace Graphics{
-class Bitmap;
+ class Bitmap;
}
+class Token;
+
namespace Gui{
// To hold images by number easier to access and reuse
typedef std::map< int, Graphics::Bitmap *> imageMap;
class Frame{
public:
Frame(const Token *token, imageMap &images) throw (LoadException);
Frame(Graphics::Bitmap *);
virtual ~Frame();
virtual void act(double xvel, double yvel);
virtual void draw(int xaxis, int yaxis, const Graphics::Bitmap &);
Graphics::Bitmap *bmp;
RelativePoint offset;
RelativePoint scrollOffset;
int time;
bool horizontalFlip;
bool verticalFlip;
int alpha;
};
class Animation{
public:
Animation(const Token *token) throw (LoadException);
/*! Load only a single bitmap (for bacwards compatibility of backgrounds in menu) */
Animation(const std::string &) throw (LoadException);
+ Animation(const AbsolutePath &) throw (LoadException);
/* use an existing bitmap */
Animation(Graphics::Bitmap * image);
virtual ~Animation();
// Logic
virtual void act();
virtual void draw(const Graphics::Bitmap &);
virtual void forwardFrame();
virtual void backFrame();
inline void reset(){ if (allowReset){ currentFrame = 0; } }
inline int getID() const { return id; }
enum Depth {
BackgroundBottom,
BackgroundMiddle,
BackgroundTop,
ForegroundBottom,
ForegroundMiddle,
ForegroundTop,
};
inline const Depth & getDepth() const { return this->depth; }
private:
int id;
Depth depth;
int ticks;
unsigned int currentFrame;
unsigned int loop;
bool allowReset;
RelativePoint axis;
// This allows the frames to scroll in place
RelativePoint velocity;
Coordinate window;
std::vector<Frame *> frames;
imageMap images;
};
}
#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jun 11, 9:56 AM (3 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
68231
Default Alt Text
(17 KB)
Attached To
Mode
R75 R-Tech1
Attached
Detach File
Event Timeline