/* rbSFML - Copyright (c) 2010 Henrik Valter Vogelius Hansson - groogy@groogy.se * This software is provided 'as-is', without any express or * implied warranty. In no event will the authors be held * liable for any damages arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute * it freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; * you must not claim that you wrote the original software. * If you use this software in a product, an acknowledgment * in the product documentation would be appreciated but * is not required. * * 2. Altered source versions must be plainly marked as such, * and must not be misrepresented as being the original software. * * 3. This notice may not be removed or altered from any * source distribution. */ #include "Sprite.hpp" #include "Vector2.hpp" #include "Rect.hpp" #include "Color.hpp" #include "main.hpp" #include VALUE globalSpriteClass; /* External classes */ extern VALUE globalVector2Class; extern VALUE globalRectClass; extern VALUE globalDrawableModule; extern VALUE globalColorClass; extern VALUE globalImageClass; static void Sprite_Free( sf::Sprite *anObject ) { delete anObject; } static VALUE Sprite_Initialize( int argc, VALUE *args, VALUE self ) { VALUE temp = Qnil; sf::Image *image = NULL; sf::Vector2f position = sf::Vector2f( 0, 0 ); sf::Vector2f scale = sf::Vector2f( 1, 1 ); float rotation = 0; sf::Color color = sf::Color::White; sf::Sprite *object = NULL; Data_Get_Struct( self, sf::Sprite, object ); switch( argc ) { case 5: temp = Color_ForceType( args[4] ); color.r = FIX2INT( Color_GetR( temp ) ); color.g = FIX2INT( Color_GetG( temp ) ); color.b = FIX2INT( Color_GetB( temp ) ); color.a = FIX2INT( Color_GetA( temp ) ); case 4: rotation = NUM2DBL( args[3] ); case 3: temp = Vector2_ForceType( args[2] ); scale.x = NUM2DBL( Vector2_GetX( temp ) ); scale.y = NUM2DBL( Vector2_GetY( temp ) ); case 2: temp = Vector2_ForceType( args[1] ); position.x = NUM2DBL( Vector2_GetX( temp ) ); position.y = NUM2DBL( Vector2_GetY( temp ) ); case 1: VALIDATE_CLASS( args[0], globalImageClass, "image" ); Data_Get_Struct( args[0], sf::Image, image ); *object = sf::Sprite( *image, position, scale, rotation, color ); rb_iv_set( self, "@__image_ref", args[0] ); case 0: break; default: rb_raise( rb_eArgError, "Expected 0..5 arguments but was given %d", argc ); } return self; } static VALUE Sprite_SetImage( int argc, VALUE *args, VALUE self ) { sf::Image *image = NULL; bool adjustToNewSize = false; sf::Sprite *object = NULL; Data_Get_Struct( self, sf::Sprite, object ); switch( argc ) { case 2: if( args[1] == Qtrue ) { adjustToNewSize = true; } else if( args[1] == Qfalse ) { adjustToNewSize = false; } else { VALIDATE_CLASS( args[1], rb_cTrueClass, "adjustToNewSize" ); } case 1: VALIDATE_CLASS( args[0], globalImageClass, "image" ); Data_Get_Struct( args[0], sf::Image, image ); object->SetImage( *image, adjustToNewSize ); rb_iv_set( self, "@__image_ref", args[0] ); break; default: rb_raise( rb_eArgError, "Expected 1 or 2 arguments but was given %d", argc ); } return Qnil; } static VALUE Sprite_SetSubRect( VALUE self, VALUE aRectangle ) { VALUE temp = Rect_ForceType( aRectangle ); sf::IntRect rectangle; rectangle.Left = FIX2INT( Rect_GetLeft( temp ) ); rectangle.Top = FIX2INT( Rect_GetTop( temp ) ); rectangle.Width = FIX2INT( Rect_GetWidth( temp ) ); rectangle.Height = FIX2INT( Rect_GetHeight( temp ) ); return Qnil; } static VALUE Sprite_Resize( int argc, VALUE *args, VALUE self ) { VALUE arg0 = Qnil; float width = 0.0f; float height = 0.0f; switch( argc ) { case 1: arg0 = Vector2_ForceType( args[0] ); width = NUM2DBL( Vector2_GetX( arg0 ) ); height = NUM2DBL( Vector2_GetY( arg0 ) ); break; case 2: width = NUM2DBL( args[0] ); height = NUM2DBL( args[1] ); break; default: rb_raise( rb_eArgError, "Expected 1 or 2 arguments but was given %d", argc ); } sf::Sprite *object = NULL; Data_Get_Struct( self, sf::Sprite, object ); object->Resize( width, height ); return Qnil; } static VALUE Sprite_FlipX( VALUE self, VALUE aFlippedFlag ) { sf::Sprite *object = NULL; Data_Get_Struct( self, sf::Sprite, object ); if( aFlippedFlag == Qtrue ) { object->FlipX( true ); } else if( aFlippedFlag == Qfalse ) { object->FlipX( false ); } else { VALIDATE_CLASS( aFlippedFlag, rb_cTrueClass, "flipped" ); } return Qnil; } static VALUE Sprite_FlipY( VALUE self, VALUE aFlippedFlag ) { sf::Sprite *object = NULL; Data_Get_Struct( self, sf::Sprite, object ); if( aFlippedFlag == Qtrue ) { object->FlipY( true ); } else if( aFlippedFlag == Qfalse ) { object->FlipY( false ); } else { VALIDATE_CLASS( aFlippedFlag, rb_cTrueClass, "flipped" ); } return Qnil; } static VALUE Sprite_GetImage( VALUE self ) { return rb_iv_get( self, "@__image_ref" ); } static VALUE Sprite_GetSubRect( VALUE self ) { sf::Sprite *object = NULL; Data_Get_Struct( self, sf::Sprite, object ); const sf::IntRect &rect = object->GetSubRect(); return rb_funcall( globalRectClass, rb_intern( "new" ), 4, INT2FIX( rect.Left ), INT2FIX( rect.Top ), INT2FIX( rect.Width ), INT2FIX( rect.Height ) ); } static VALUE Sprite_GetSize( VALUE self ) { sf::Sprite *object = NULL; Data_Get_Struct( self, sf::Sprite, object ); const sf::Vector2f size = object->GetSize(); return rb_funcall( globalVector2Class, rb_intern( "new" ), 2, rb_float_new( size.x ), rb_float_new( size.y ) ); } static VALUE Sprite_GetPixel( VALUE self, VALUE aX, VALUE aY ) { sf::Sprite *object = NULL; Data_Get_Struct( self, sf::Sprite, object ); const sf::Color color = object->GetPixel( FIX2UINT( aX ), FIX2UINT( aY ) ); return rb_funcall( globalColorClass, rb_intern( "new" ), 4, INT2FIX( color.r ), INT2FIX( color.g ), INT2FIX( color.b ), INT2FIX( color.a ) ); } static VALUE Sprite_New( int argc, VALUE *args, VALUE aKlass ) { sf::Sprite *object = new sf::Sprite(); VALUE rbData = Data_Wrap_Struct( aKlass, 0, Sprite_Free, object ); rb_obj_call_init( rbData, argc, args ); return rbData; } void Init_Sprite( void ) { /* SFML namespace which contains the classes of this module. */ VALUE sfml = rb_define_module( "SFML" ); /* Drawable representation of an image, with its own transformations, color, blend mode, etc. * * SFML::Sprite is a drawable class that allows to easily display an image (or a part of it) on a render target. * * It inherits all the functions from SFML::Drawable: position, rotation, scale, origin, global color and blend mode. * It also adds sprite-specific properties such as the image to use, the part of it to display, and some convenience * functions to flip or resize the sprite. * * SFML::Sprite works in combination with the SFML::Image class, which loads and provides the pixel data of a * given image. * * The separation of SFML::Sprite and SFML::Image allows more flexibility and better performances: indeed a SFML::Image * is a heavy resource, and any operation on it is slow (often too slow for real-time applications). On the other side, * a SFML::Sprite is a lightweight object which can use the pixel data of a SFML::Image and draw it with its own * transformation / color / blending attributes. * * It is important to note that the SFML::Sprite instance doesn't copy the image that it uses, it only keeps a reference * to it. Thus, a SFML::Image must not be destructed while it is used by a SFML::Sprite (i.e. never write a function that * uses a local SFML::Image instance for creating a sprite). * * NOTE: This is the ruby bindings so the images will be managed by the ruby garbage collector and thus the image won't * be destructed until all sprites referencing it is destructed. But it's still a good practice to keep in mind. * * Usage example: * * # Declare and load an image * image = SFML::Image.new * image.loadFromFile( "image.png" ) * * # Create a sprite * sprite = SFML::Sprite.new * sprite.image = image * sprite.subRect = [10, 10, 50, 30] * sprite.resize( 100, 60 ) * * # Display it * window.draw( sprite ) # window is a SFML::RenderWindow * */ globalSpriteClass = rb_define_class_under( sfml, "Sprite", rb_cObject ); rb_include_module( globalSpriteClass, globalDrawableModule ); // Class methods rb_define_singleton_method( globalSpriteClass, "new", Sprite_New, -1 ); // Instance methods rb_define_method( globalSpriteClass, "initialize", Sprite_Initialize, -1 ); rb_define_method( globalSpriteClass, "setImage", Sprite_SetImage, -1 ); rb_define_method( globalSpriteClass, "setSubRect", Sprite_SetSubRect, 1 ); rb_define_method( globalSpriteClass, "resize", Sprite_Resize, -1 ); rb_define_method( globalSpriteClass, "flipX", Sprite_FlipX, 1 ); rb_define_method( globalSpriteClass, "flipY", Sprite_FlipY, 1 ); rb_define_method( globalSpriteClass, "getImage", Sprite_GetImage, 0 ); rb_define_method( globalSpriteClass, "getSubRect", Sprite_GetSubRect, 0 ); rb_define_method( globalSpriteClass, "getSize", Sprite_GetSize, 0 ); rb_define_method( globalSpriteClass, "getPixel", Sprite_GetPixel, 2 ); // Instance Aliases rb_define_alias( globalSpriteClass, "image=", "setImage" ); rb_define_alias( globalSpriteClass, "set_image", "setImage" ); rb_define_alias( globalSpriteClass, "image", "getImage" ); rb_define_alias( globalSpriteClass, "get_image", "getImage" ); rb_define_alias( globalSpriteClass, "subRect=", "setSubRect" ); rb_define_alias( globalSpriteClass, "sub_rect=", "setSubRect" ); rb_define_alias( globalSpriteClass, "subRect", "getSubRect" ); rb_define_alias( globalSpriteClass, "sub_rect", "getSubRect" ); rb_define_alias( globalSpriteClass, "flip_x", "flipX" ); rb_define_alias( globalSpriteClass, "flip_y", "flipY" ); rb_define_alias( globalSpriteClass, "flip_x=", "flipX" ); rb_define_alias( globalSpriteClass, "flip_y=", "flipY" ); rb_define_alias( globalSpriteClass, "flipX=", "flipX" ); rb_define_alias( globalSpriteClass, "flipY=", "flipY" ); rb_define_alias( globalSpriteClass, "get_size", "getSize" ); rb_define_alias( globalSpriteClass, "size", "getSize" ); rb_define_alias( globalSpriteClass, "get_pixel", "getPixel" ); }