1 #include "Animation.h"
2 
3 #include <cmath>
4 
5 namespace love_opengl
6 {
Animation(pImage image)7 	Animation::Animation(pImage image) : image(image), mode(1), current(0), playing(true),
8 		timeBuffer(0), direction(1), speed(1.0f)
9 	{
10 	}
11 
Animation(pImage image,float fw,float fh,float delay,int num)12 	Animation::Animation(pImage image, float fw, float fh, float delay, int num) :
13 	image(image), mode(1), current(0), playing(true), timeBuffer(0), direction(1), speed(1.0f)
14 	{
15 		// Generate frames.
16 		int w = (int)(image->getWidth()/fw);
17 		int h = (int)(image->getHeight()/fh);
18 
19 		int real_num = (num == 0) ? (w * h) : num;
20 		if(real_num > (w * h)) real_num = (w * h);
21 
22 		for(int i = 0;i<real_num;i++)
23 		{
24 			int x = (int)((i % w)*fw);
25 			int y = (int)((i/w)*fh);
26 
27 			addFrame((float)x, (float)y, fw, fh, delay);
28 		}
29 	}
30 
~Animation()31 	Animation::~Animation()
32 	{
33 	}
34 
addFrame(float x,float y,float w,float h,float delay)35 	void Animation::addFrame(float x, float y, float w, float h, float delay)
36 	{
37 		// Add delay.
38 		delays.push_back(delay);
39 
40 		// Add frame.
41 		frame f;
42 		f.x = x; f.y = y;
43 		f.width = w;
44 		f.height = h;
45 		f.post_delay = (int)delays.size() - 1;
46 
47 		float xTex = x/(float)image->getTextureWidth();
48 		float yTex = y/(float)image->getTextureHeight();
49 
50 		float wTex = w/(float)image->getTextureWidth();
51 		float hTex = h/(float)image->getTextureHeight();
52 
53 		f.vertices[0] = 0; f.vertices[1] = 0;
54 		f.vertices[2] = 0; f.vertices[3] = floor(h);
55 		f.vertices[4] = floor(w); f.vertices[5] = floor(h);
56 		f.vertices[6] = floor(w); f.vertices[7] = 0;
57 
58 		f.texels[0] = xTex; f.texels[1] = yTex;
59 		f.texels[2] = xTex; f.texels[3] = yTex+hTex;
60 		f.texels[4] = xTex+wTex; f.texels[5] = yTex+hTex;
61 		f.texels[6] = xTex+wTex; f.texels[7] = yTex;
62 
63 		frames.push_back(f);
64 
65 		if(frames.size() > 1)
66 		{
67 			frames.back().pre_delay = frames[frames.size() - 2].post_delay;
68 
69 			// Update delay of first frame.
70 			frames.front().pre_delay = frames.back().post_delay;
71 		}
72 
73 	}
74 
setMode(int mode)75 	void Animation::setMode(int mode)
76 	{
77 		this->mode = mode;
78 	}
79 
play()80 	void Animation::play()
81 	{
82 		playing = true;
83 	}
84 
stop()85 	void Animation::stop()
86 	{
87 		playing = false;
88 	}
89 
reset()90 	void Animation::reset()
91 	{
92 		current = 0;
93 		timeBuffer = 0;
94 	}
95 
seek(int frame)96 	void Animation::seek(int frame)
97 	{
98 		if(frame >= 0 && frame < (int)frames.size())
99 			current = frame;
100 	}
101 
getCurrentFrame() const102 	int Animation::getCurrentFrame() const
103 	{
104 		return current;
105 	}
106 
getSize() const107 	int Animation::getSize() const
108 	{
109 		return (int)frames.size();
110 	}
111 
setDelay(int frame,float delay)112 	void Animation::setDelay(int frame, float delay)
113 	{
114 		if(frame >= 0 && frame < (int)frames.size())
115 			delays[frames[0].post_delay] = delay;
116 	}
117 
setSpeed(float speed)118 	void Animation::setSpeed(float speed)
119 	{
120 		this->speed = speed;
121 	}
122 
getSpeed() const123 	float Animation::getSpeed() const
124 	{
125 		return speed;
126 	}
127 
bind() const128 	void Animation::bind() const
129 	{
130 		image->bind();
131 	}
132 
update(float dt)133 	void Animation::update(float dt)
134 	{
135 		if(!playing)
136 			return;
137 
138 		if(frames.size() <= 0)
139 			return;
140 
141 		timeBuffer += (dt * speed);
142 
143 		int next;
144 		float d;
145 
146 		switch(mode)
147 		{
148 		case love::ANIMATION_LOOP:
149 			next = current;
150 			while(timeBuffer >= delays[frames[current].post_delay])
151 			{
152 				timeBuffer -= delays[frames[current].post_delay];
153 				if(++next >= (int)frames.size())
154 					next = 0;
155 			}
156 			current = next;
157 			break;
158 		case love::ANIMATION_PLAY_ONCE:
159 			next = current;
160 			while(timeBuffer >= delays[frames[current].post_delay])
161 			{
162 				timeBuffer -= delays[frames[current].post_delay];
163 				if(++next >= (int)frames.size())
164 				{
165 					next--;
166 					playing = false;
167 					timeBuffer = 0;
168 				}
169 			}
170 			current = next;
171 			break;
172 		case love::ANIMATION_BOUNCE:
173 			next = current;
174 			d = (direction == 1) ? delays[frames[next].post_delay] : delays[frames[next].pre_delay];
175 
176 			while(timeBuffer >= d)
177 			{
178 				timeBuffer -= d;
179 				next += direction;
180 				if(next < 0 || next >= (int)frames.size())
181 				{
182 					direction *= -1;
183 					next += direction;
184 				}
185 				d = (direction == 1) ? delays[frames[next].post_delay] : delays[frames[next].pre_delay];
186 			}
187 			current = next;
188 			break;
189 		}
190 
191 		// Set the current width/height.
192 		this->width = frames[current].width;
193 		this->height = frames[current].height;
194 	}
195 
draw(float x,float y) const196 	void Animation::draw(float x, float y) const
197 	{
198 		if(frames.size() <= 0)
199 			return;
200 
201 		const frame & f = frames[current];
202 		image->draw(f.vertices, f.texels, x, y, 0, 1, 1, -f.width/2.0f + center_x, -f.height/2.0f + center_y, love::FLIP_NONE);
203 	}
204 
draw(float x,float y,float angle,float sx,float sy,int flip) const205 	void Animation::draw(float x, float y, float angle, float sx, float sy, int flip) const
206 	{
207 		if(frames.size() <= 0)
208 			return;
209 
210 		const frame & f = frames[current];
211 		image->draw(f.vertices, f.texels, x, y, angle, sx, sy, -f.width/2.0f + center_x, -f.height/2.0f + center_y, flip);
212 	}
213 } // love_opengl
214