00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "sprite.h"
00026 #include <SDL.h>
00027 #include <SDL_rotozoom.h>
00028 #include <iostream>
00029 #include "surface.h"
00030 #include "../game/game.h"
00031 #include "../include/app.h"
00032 #include "../map/camera.h"
00033 #include "../map/map.h"
00034 #include "../tool/rectangle.h"
00035 #include "../tool/debug.h"
00036
00037 #define BUGGY_SDLGFX
00038
00039 Sprite::Sprite() :
00040 cache(*this),
00041 animation(*this)
00042 {
00043 Constructor();
00044 }
00045
00046 Sprite::Sprite( Surface surface ) :
00047 cache(*this),
00048 animation(*this)
00049 {
00050 Constructor();
00051 frame_width_pix = surface.GetWidth();
00052 frame_height_pix = surface.GetHeight();
00053 frames.push_back( SpriteFrame(surface));
00054 }
00055
00056 Sprite::Sprite(const Sprite &other) :
00057 cache(*this),
00058 animation(other.animation,*this)
00059 {
00060 frame_width_pix = other.frame_width_pix;
00061 frame_height_pix = other.frame_height_pix;
00062 scale_x = other.scale_x;
00063 scale_y = other.scale_y;
00064 alpha = other.alpha;
00065 rotation_rad = other.rotation_rad;
00066 current_frame = other.current_frame;
00067 rot_hotspot = other.rot_hotspot;
00068 show = other.show;
00069
00070 for(unsigned int f=0;f<other.frames.size();f++)
00071 AddFrame(other.frames[f].surface,other.frames[f].delay);
00072 }
00073
00074 void Sprite::Constructor() {
00075 show = true;
00076 current_frame = 0;
00077 frame_width_pix = frame_height_pix = 0;
00078 alpha = 1.0f;
00079 scale_x = scale_y = 1.0f;
00080 rotation_rad = 0.0f;
00081 SetRotation_HotSpot(center);
00082 }
00083
00084 void Sprite::Init(Surface& surface, const Point2i &frameSize, int nb_frames_x, int nb_frames_y){
00085 Point2i f;
00086
00087 this->frame_width_pix = frameSize.x;
00088 this->frame_height_pix = frameSize.y;
00089
00090 surface.SetAlpha( 0, 0);
00091
00092 for( f.y = 0; f.y < nb_frames_y; f.y++)
00093 for( f.x = 0; f.x < nb_frames_x; f.x++){
00094 Surface new_surf = Surface(frameSize, SDL_SWSURFACE|SDL_SRCALPHA, true);
00095 Rectanglei sr(f * frameSize, frameSize);
00096
00097 new_surf.Blit( surface, sr, Point2i(0, 0));
00098 frames.push_back( SpriteFrame(new_surf));
00099 }
00100 }
00101
00102 void Sprite::AddFrame(const Surface &surf, unsigned int delay){
00103 frames.push_back( SpriteFrame(surf, delay) );
00104 }
00105
00106 void Sprite::SetSize(unsigned int w, unsigned int h){
00107 assert(frame_width_pix == 0 && frame_height_pix == 0)
00108 frame_width_pix = w;
00109 frame_height_pix = h;
00110 }
00111
00112 void Sprite::SetSize(const Point2i &size){
00113 SetSize(size.x, size.y);
00114 }
00115
00116 unsigned int Sprite::GetWidth() const{
00117 return static_cast<uint>(frame_width_pix * (scale_x>0?scale_x:-scale_x));
00118 }
00119
00120 unsigned int Sprite::GetWidthMax() const{
00121 if(!current_surface.IsNull() )
00122 return current_surface.GetWidth();
00123 else
00124 return GetWidth();
00125 }
00126
00127 unsigned int Sprite::GetHeight() const{
00128 return static_cast<uint>(frame_height_pix * (scale_y>0?scale_y:-scale_y));
00129 }
00130
00131 unsigned int Sprite::GetHeightMax() const{
00132 if(!current_surface.IsNull() )
00133 return current_surface.GetHeight();
00134 else
00135 return GetHeight();
00136 }
00137
00138 Point2i Sprite::GetSize() const{
00139 return Point2i(GetWidth(), GetHeight());
00140 }
00141
00142 Point2i Sprite::GetSizeMax() const{
00143 return Point2i(GetWidthMax(), GetHeightMax());
00144 }
00145
00146 unsigned int Sprite::GetFrameCount(){
00147 return frames.size();
00148 }
00149
00150 void Sprite::SetCurrentFrame( unsigned int frame_no){
00151 assert (frame_no < frames.size());
00152 if (current_frame != frame_no) {
00153 cache.InvalidLastFrame();
00154 MSG_DEBUG("sprite", "Set current frame : %d", frame_no);
00155 }
00156 current_frame = frame_no;
00157 }
00158
00159 unsigned int Sprite::GetCurrentFrame() const{
00160 assert(current_frame < frames.size());
00161 return current_frame;
00162 }
00163
00164 SpriteFrame& Sprite::operator[] (unsigned int index){
00165 return frames.at(index);
00166 }
00167
00168 const SpriteFrame& Sprite::operator[] (unsigned int index) const{
00169 return frames.at(index);
00170 }
00171
00172 const SpriteFrame& Sprite::GetCurrentFrameObject() const{
00173 return frames[current_frame];
00174 }
00175
00176 void Sprite::Scale( float scale_x, float scale_y){
00177 if(this->scale_x == scale_x && this->scale_y == scale_y)
00178 return;
00179 this->scale_x = scale_x;
00180 this->scale_y = scale_y;
00181 cache.InvalidLastFrame();
00182 }
00183
00184 void Sprite::ScaleSize(int width, int height){
00185 Scale(float(width)/float(frame_width_pix),
00186 float(height)/float(frame_height_pix));
00187 }
00188
00189 void Sprite::ScaleSize(Point2i size){
00190 ScaleSize(size.x, size.y);
00191 }
00192
00193 void Sprite::GetScaleFactors( float &scale_x, float &scale_y){
00194 scale_x = this->scale_x;
00195 scale_y = this->scale_y;
00196 }
00197
00198 void Sprite::SetFrameSpeed(unsigned int nv_fs){
00199 for ( unsigned int f = 0 ; f < frames.size() ; f++)
00200 frames[f].delay = nv_fs;
00201 }
00202
00203 void Sprite::SetAlpha( float alpha){
00204 assert(alpha >= 0.0 && alpha <= 1.0);
00205 if(this->alpha == alpha)
00206 return;
00207 this->alpha = alpha;
00208 }
00209
00210 float Sprite::GetAlpha(){
00211 return alpha;
00212 }
00213
00214 void Sprite::SetRotation_rad( double angle_rad){
00215 while(angle_rad > 2*M_PI)
00216 angle_rad -= 2 * M_PI;
00217 while(angle_rad <= -2*M_PI)
00218 angle_rad += 2 * M_PI;
00219
00220 if(rotation_rad == angle_rad) return;
00221
00222 rotation_rad = angle_rad;
00223 cache.InvalidLastFrame();
00224 }
00225
00226 const double &Sprite::GetRotation_rad()
00227 {
00228 assert(rotation_rad > -2*M_PI && rotation_rad <= 2*M_PI);
00229 return rotation_rad;
00230 }
00231
00232 void Sprite::SetRotation_HotSpot( const Point2i new_hotspot)
00233 {
00234 rot_hotspot = user_defined;
00235 rhs_pos = new_hotspot;
00236
00237 if( rhs_pos.x * 2 == static_cast<int>(GetWidth()) &&
00238 rhs_pos.y * 2 == static_cast<int>(GetHeight()) )
00239 rot_hotspot = center;
00240 }
00241
00242 void Sprite::Calculate_Rotation_Offset(Surface& tmp_surface){
00243 const SpriteFrame& frame = GetCurrentFrameObject();
00244 const Surface &surface = frame.surface;
00245
00246
00247 int surfaceHeight = surface.GetHeight();
00248 int surfaceWidth = surface.GetWidth();
00249
00250
00251 rotation_point.x = surfaceWidth / 2 - tmp_surface.GetWidth() / 2;
00252 rotation_point.y = surfaceHeight / 2 - tmp_surface.GetHeight() / 2;
00253
00254 if(rot_hotspot == center)
00255 return;
00256
00257 if(rot_hotspot != user_defined)
00258 {
00259 switch(rot_hotspot)
00260 {
00261 case top_left: rhs_pos = Point2i( 0, 0); break;
00262 case top_center: rhs_pos = Point2i( surfaceWidth/2, 0); break;
00263 case top_right: rhs_pos = Point2i( surfaceWidth, 0); break;
00264 case left_center: rhs_pos = Point2i( 0, surfaceHeight/2); break;
00265 case center: rhs_pos = Point2i( surfaceWidth/2, surfaceHeight/2); break;
00266 case right_center: rhs_pos = Point2i( surfaceWidth, surfaceHeight/2); break;
00267 case bottom_left: rhs_pos = Point2i( 0, surfaceHeight); break;
00268 case bottom_center: rhs_pos = Point2i( surfaceWidth/2, surfaceHeight); break;
00269 case bottom_right: rhs_pos = Point2i( surfaceWidth, surfaceHeight); break;
00270 default:
00271 assert(false);
00272 }
00273 }
00274
00275 Point2i rhs_pos_tmp;
00276 rhs_pos_tmp.x = static_cast<uint>(rhs_pos.x * scale_x);
00277 rhs_pos_tmp.y = static_cast<uint>(rhs_pos.y * scale_y);
00278 surfaceWidth = static_cast<uint>(surfaceWidth * scale_x);
00279 surfaceHeight = static_cast<uint>(surfaceHeight * scale_y);
00280
00281
00282 float rhs_dst;
00283 double rhs_angle;
00284
00285 rhs_dst = sqrt(float((surfaceWidth /2 - rhs_pos_tmp.x)*(surfaceWidth /2 - rhs_pos_tmp.x)
00286 + (surfaceHeight/2 - rhs_pos_tmp.y)*(surfaceHeight/2 - rhs_pos_tmp.y)));
00287
00288 if( rhs_dst == 0.0)
00289 rhs_angle = 0.0;
00290 else
00291 rhs_angle = - acos ( float(rhs_pos_tmp.x - surfaceWidth/2) / rhs_dst );
00292
00293 if(surfaceHeight/2 - rhs_pos.y < 0) rhs_angle = -rhs_angle;
00294
00295 rhs_angle += rotation_rad;
00296
00297 Point2i rhs_new_pos = Point2i(surfaceWidth /2 + static_cast<uint>(cos(rhs_angle) * rhs_dst),
00298 surfaceHeight/2 + static_cast<uint>(sin(rhs_angle) * rhs_dst));
00299
00300 rotation_point.x -= rhs_new_pos.x;
00301 rotation_point.y -= rhs_new_pos.y;
00302 rotation_point.x += rhs_pos_tmp.x;
00303 rotation_point.y += rhs_pos_tmp.y;
00304 }
00305
00306 void Sprite::Start(){
00307 show = true;
00308 animation.Start();
00309 cache.InvalidLastFrame();
00310 }
00311
00312 void Sprite::Blit( Surface &dest, uint pos_x, uint pos_y){
00313 RefreshSurface();
00314 Blit(dest, pos_x, pos_y, 0, 0, current_surface.GetWidth(), current_surface.GetHeight());
00315 }
00316
00317 void Sprite::Blit( Surface &dest, const Point2i &pos){
00318 Blit(dest, pos.GetX(), pos.GetY());
00319 }
00320
00321 void Sprite::Blit( Surface &dest, const Rectanglei &srcRect, const Point2i &destPos){
00322 Blit(dest, destPos.GetX(), destPos.GetY(), srcRect.GetPositionX(), srcRect.GetPositionY(), srcRect.GetSizeX(), srcRect.GetSizeY() );
00323 }
00324
00325 void Sprite::Blit( Surface &dest, int pos_x, int pos_y, int src_x, int src_y, uint w, uint h){
00326 if (!show)
00327 return;
00328
00329 RefreshSurface();
00330
00331 Rectanglei srcRect (src_x, src_y, w, h);
00332 Rectanglei dstRect (pos_x + rotation_point.x, pos_y + rotation_point.y, w, h);
00333
00334 if(alpha == 1.0)
00335 dest.Blit(current_surface, srcRect, dstRect.GetPosition());
00336 else
00337 {
00338 Surface surf_alpha;
00339 surf_alpha.NewSurface(srcRect.GetSize(),SDL_SWSURFACE,false);
00340 surf_alpha.Blit(dest,dstRect,Point2i(0,0));
00341 surf_alpha.SetAlpha(SDL_SRCALPHA, (int)(alpha * 255.0));
00342 surf_alpha.Blit(current_surface,srcRect,Point2i(0,0));
00343 dest.Blit(surf_alpha, srcRect, dstRect.GetPosition());
00344 }
00345
00346
00347 if( Game::GetInstance()->IsGameLaunched() )
00348 world.ToRedrawOnScreen( dstRect );
00349 }
00350
00351 void Sprite::Finish(){
00352 animation.Finish();
00353 switch(animation.GetShowOnFinish())
00354 {
00355 case SpriteAnimation::show_first_frame:
00356 current_frame = 0;
00357 break;
00358 case SpriteAnimation::show_blank:
00359 show = false;
00360 break;
00361 default:
00362 case SpriteAnimation::show_last_frame:
00363 current_frame = frames.size()-1;
00364 break;
00365 }
00366 cache.InvalidLastFrame();
00367 }
00368
00369 void Sprite::Update(){
00370 animation.Update();
00371 }
00372
00373 void Sprite::Draw(const Point2i &pos){
00374 DrawXY(pos - camera.GetPosition());
00375 }
00376
00377 void Sprite::DrawXY(const Point2i &pos){
00378 if( !show )
00379 return;
00380
00381 Blit(AppWormux::GetInstance()->video.window, pos);
00382 }
00383
00384 void Sprite::Show() { show = true; }
00385 void Sprite::Hide() { show = false; }
00386 bool Sprite::IsFinished() const { return animation.IsFinished(); }
00387
00388 void Sprite::EnableRotationCache(unsigned int cache_size) {
00389 cache.EnableRotationCache(frames, cache_size);
00390 }
00391
00392 void Sprite::EnableFlippingCache() {
00393 cache.EnableFlippingCache(frames);
00394 }
00395
00396 void Sprite::RefreshSurface()
00397 {
00398 current_surface.Free();
00399
00400 if(!cache.have_rotation_cache && !cache.have_flipping_cache)
00401 {
00402 if(!cache.have_lastframe_cache)
00403 current_surface = frames[current_frame].surface.RotoZoom(-rotation_rad, scale_x, scale_y, SMOOTHING_OFF);
00404 else
00405 {
00406 if(cache.last_frame.IsNull() )
00407 {
00408 #ifdef BUGGY_SDLGFX
00409 if(rotation_rad != 0.0 || (scale_x != 1.0 && scale_y == 1.0))
00410 {
00411 current_surface = frames[current_frame].surface.RotoZoom(-rotation_rad , scale_x, scale_y, SMOOTHING_OFF);
00412 cache.last_frame = current_surface;
00413 }
00414 else
00415 if(scale_x != 1.0 || scale_y != 1.0)
00416 {
00417 #endif
00418 current_surface = frames[current_frame].surface.RotoZoom(-rotation_rad, scale_x, scale_y, SMOOTHING_ON);
00419 cache.last_frame = current_surface;
00420 #ifdef BUGGY_SDLGFX
00421 }
00422 else
00423 {
00424 current_surface = frames[current_frame].surface;
00425 cache.last_frame.Free();
00426 }
00427 #endif
00428 }
00429 else
00430 {
00431 current_surface = cache.last_frame;
00432 }
00433 }
00434 }
00435 else
00436 {
00437 if(cache.have_flipping_cache && !cache.have_rotation_cache)
00438 {
00439 if(rotation_rad != 0.0 || scale_y != 1.0 || (scale_x != 1.0 && scale_x != -1.0))
00440 {
00441 current_surface = frames[current_frame].surface.RotoZoom( rotation_rad, scale_x, scale_y, SMOOTHING_OFF );
00442 }
00443 else
00444 if(scale_x == 1.0)
00445 current_surface = frames[current_frame].surface;
00446 else
00447 current_surface = cache.frames[current_frame].flipped_surface;
00448 }
00449 else
00450 if(!cache.have_flipping_cache && cache.have_rotation_cache)
00451 {
00452 if(scale_x != 1.0 || scale_y != 1.0)
00453 current_surface = frames[current_frame].surface.RotoZoom(rotation_rad, scale_x, scale_y, SMOOTHING_OFF);
00454 else
00455 current_surface = cache.frames[current_frame].GetSurfaceForAngle(rotation_rad);
00456 }
00457 else
00458 {
00459
00460 if((scale_x != 1.0 && scale_x != -1.0) || scale_y != 1.0)
00461 current_surface = frames[current_frame].surface.RotoZoom( rotation_rad, scale_x, scale_y, SMOOTHING_OFF);
00462 else
00463 {
00464
00465 if(scale_x == 1.0)
00466 current_surface = cache.frames[current_frame].GetSurfaceForAngle(rotation_rad);
00467 else
00468 current_surface = cache.frames[current_frame].GetFlippedSurfaceForAngle(rotation_rad);
00469 }
00470 }
00471 }
00472 assert( !current_surface.IsNull() );
00473
00474
00475 rotation_point.x=0;
00476 rotation_point.y=0;
00477 if(rot_hotspot != center || rotation_rad!=0.0)
00478 Calculate_Rotation_Offset(current_surface);
00479 }
00480
00481 Surface Sprite::GetSurface() {
00482 assert ( !current_surface.IsNull() );
00483 return current_surface;
00484 }
00485