So... Alot of changes...
[potpourri.git] / src / Sprite.cpp
blobdf04375e17da0e0a42e7e0bbe2f5d45ec387f3fd
1 // Copyright 2008 Brian Caine && Justin Overfelt
3 // This file is part of Potpourri.
5 // Potpourri is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
10 // Potpourri is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTIBILITY of FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Potpourri. If not, see <http://www.gnu.org/licenses/>.
18 // NOTES:
20 // See Sprite.h
22 #include <iostream>
23 #include <cmath>
25 #include <SDL/SDL_rotozoom.h>
27 #include "Sprite.h"
29 #define PI 3.141592653589793
31 using namespace fragrant;
33 Sprite* Sprite::makeSprite(std::vector<SDL_Surface*> dframes,
34 SpriteParams dparams)
36 Sprite* the_sprite = new Sprite(dframes, dparams);
38 if (!was_made)
40 delete the_sprite;
41 the_sprite = 0;
42 std::cerr << "Sprite::makeSprite(): Error making sprite" << std::endl;
45 was_made = false;
47 return the_sprite;
50 Sprite::~Sprite()
52 std::map<int, std::vector<SDL_Surface*> >::iterator biter;
53 std::vector<SDL_Surface*>::iterator niter;
55 for (biter = angle_frames.begin(); biter != angle_frames.end(); biter++)
56 for (niter = biter->second.begin(); niter != biter->second.end(); niter++)
58 SDL_FreeSurface(*niter);
62 void Sprite::draw(SDL_Surface* dest)
64 // timing stuff
66 int cur_ticks = SDL_GetTicks();
67 ticks_left -= (cur_ticks - last_tick);
69 last_tick = cur_ticks;
71 while (ticks_left <= 0)
73 cur_frame++;
74 if (cur_frame == frames.size() && sequence.repeat)
75 cur_frame = 0;
77 ticks_left = sequence.frames.at(cur_frame).duration + ticks_left;
80 // rotation stuff
81 std::map<int, std::vector<SDL_Surface*> >::iterator iter;
83 std::vector<SDL_Surface*> cocked_frames;
85 for (iter = angle_frames.begin(); iter != angle_frames.end(); iter++)
87 if ((sequence.angle + ANGLE_SNAP > iter->first) &&
88 (sequence.angle - ANGLE_SNAP < iter->first))
89 cocked_frames = iter->second;
92 if (!cocked_frames.size())
94 makeNewAngleFrame(sequence.angle);
95 cocked_frames = angle_frames[sequence.angle];
98 // actual rendering
100 SDL_Surface* surface = cocked_frames.at(cur_frame);
102 SDL_Rect pos = {sequence.position.at(0) + angle_offset.at(0),
103 sequence.position.at(1) + angle_offset.at(1),
104 surface->w, surface->h};
105 SDL_BlitSurface(surface, 0, dest, &pos);
107 return;
110 int Sprite::getCurrentFrame()
112 return cur_frame;
115 int Sprite::getAngle()
117 return sequence.angle;
120 void Sprite::setAngle(int new_angle)
122 sequence.angle = new_angle;
123 sequence.angle %= 360;
124 calcAngleOffset();
125 return;
128 std::vector<int> Sprite::getPosition()
130 return sequence.position;
133 void Sprite::setPosition(std::vector<int> new_position)
135 if (new_position.size() < 2)
137 std::cerr << "Sprite::setPosition(): Not enough parameters for "
138 << "new position" << std::endl;
139 return;
142 if (new_position.size() > 2)
144 std::cerr << "Sprite::setPosition(): Too many parameters for new "
145 << "position" << std::endl;
148 sequence.position = new_position;
150 return;
153 Sprite::Sprite(std::vector<SDL_Surface*> dframes, SpriteParams dparams)
155 was_made = true;
157 if (!dframes.size() || !dparams.frames.size())
158 was_made = false;
160 std::vector<Frame>::iterator iter;
161 for (iter = dparams.frames.begin(); iter != dparams.frames.end(); iter++)
162 if (iter->frame >= dframes.size())
163 was_made = false;
165 if ((dparams.position.size() < 2) || (dparams.focal_point.size() < 2))
166 was_made = false;
168 if (dparams.position.size() > 2)
169 std::cerr << "Sprite::makeSprite(): Warning, More position "
170 << "parameters then needed..." << std::endl;
172 if (dparams.focal_point.size() > 2)
173 std::cerr << "Sprite::makeSprite(): Warning, More focal point "
174 << "parameters then needed..." << std::endl;
176 if (dparams.angle > 360)
178 std::cerr << "Sprite::makeSprite(): Warning, Angle is greater than 360, "
179 << "wrapping around..." << std::endl;
180 dparams.angle %= 360;
183 int w, h;
184 std::vector<SDL_Surface*>::iterator inc;
185 bool frame_size = true;
187 w = dframes.at(0) -> w;
188 h = dframes.at(0) -> h;
190 for (inc = dframes.begin(); inc != dframes.end(); inc++)
191 frame_size = ((*inc)-> w == w) && ((*inc) -> h == h) && (frame_size);
193 if (!frame_size)
195 std::cerr << "Sprite::makeSprite(): Warning, not all frames are the same size"
196 << std::endl;
199 was_made = was_made && frame_size;
201 if (was_made)
203 sequence = dparams;
204 frames = dframes;
206 cur_frame = 0;
207 last_tick = -1;
208 ticks_left = -1;
210 makeAngleFrames();
211 calcAngleOffset();
215 bool Sprite::makeAngleFrames()
217 int cur;
219 for (cur = 0; cur < CIRCLE; cur += ANGLE_CACHE)
220 makeNewAngleFrame(cur);
222 return true;
225 void Sprite::makeNewAngleFrame(int angle)
227 SDL_Surface* temp;
229 std::vector<SDL_Surface*> new_frames;
231 std::vector<SDL_Surface*>::iterator iter;
233 for (iter = frames.begin(); iter != frames.end(); iter++)
235 temp = rotozoomSurface(*iter, static_cast<double>(angle), 1, 1);
236 SDL_SetAlpha(temp, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
237 new_frames.push_back(temp);
240 angle_frames[angle] = new_frames;
242 return;
245 void Sprite::calcAngleOffset()
247 int rot = -1;
248 SDL_Surface* temp_surf = 0;
250 std::map<int, std::vector<SDL_Surface*> >::iterator iter;
251 for (iter = angle_frames.begin(); iter != angle_frames.end(); iter++)
252 if ((sequence.angle + ANGLE_SNAP > iter->first) &&
253 (sequence.angle - ANGLE_SNAP < iter->first))
255 rot = iter->first;
256 temp_surf = iter->second.at(0);
259 if (!temp_surf)
260 return;
262 float c_1[2], c_2[2], c_3[2];
263 float center_1[2], center_2[2];
264 float size_1[2], size_2[2];
265 float focus_1[2], focus_2[2], focus_3[2], focus_4[2];
266 float radius_1, radius_2, theta_1, theta_2, theta_3;
268 size_1[0] = frames.at(cur_frame)->w;
269 size_1[1] = frames.at(cur_frame)->h;
271 size_2[0] = temp_surf->w;
272 size_2[1] = temp_surf->h;
274 focus_1[0] = sequence.focal_point.at(0);
275 focus_1[1] = sequence.focal_point.at(1);
277 c_1[0] = 0;
278 c_1[1] = 0;
280 center_1[0] = size_1[0] / 2;
281 center_1[1] = size_1[1] / 2;
283 center_2[0] = size_2[0] / 2;
284 center_2[1] = size_2[1] / 2;
286 radius_1 = sqrt(
287 static_cast<double>(pow(center_1[0], 2) + pow(center_1[1], 2)));
288 theta_1 = acos(-center_1[0] / radius_1) * (180/PI);
290 c_2[0] = radius_1 * cos((theta_1 + rot) * (PI/180));
291 c_2[1] = radius_1 * sin((theta_1 + rot) * (PI/180));
293 c_3[0] = c_2[0] + center_2[0];
294 c_3[1] = center_2[1] - c_2[1];
296 radius_2 = sqrt(
297 static_cast<double>(pow(focus_1[0], 2) + pow(focus_1[1], 2)));
298 if (radius_2)
299 theta_2 = -acos(focus_1[0] / radius_2) * (180/PI);
300 else
301 theta_2 = 0;
303 theta_3 = theta_2 + rot;
305 focus_2[0] = radius_2 * cos(theta_3 * (PI/180));
306 focus_2[1] = radius_2 * sin(theta_3 * (PI/180));
308 focus_3[0] = c_3[0] + focus_2[0];
309 focus_3[1] = c_3[1] - focus_2[1];
311 focus_4[0] = focus_1[0] - focus_3[0];
312 focus_4[1] = focus_1[0] - focus_3[1];
314 angle_offset.clear();
315 angle_offset.push_back(static_cast<int>(focus_4[0]));
316 angle_offset.push_back(static_cast<int>(focus_4[1]));
318 return;
321 bool Sprite::was_made = false;