/* 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 "View.hpp" #include "Vector2.hpp" #include "Rect.hpp" #include "main.hpp" #include VALUE globalViewClass; /* External classes */ extern VALUE globalRectClass; extern VALUE globalVector2Class; static void View_Free( sf::View *anObject ) { delete anObject; } /* call-seq: * View.new() -> view * View.new( rectangle ) -> view * View.new( center, size ) -> view * * Construct a view. */ static VALUE View_Initialize( int argc, VALUE *args, VALUE self ) { VALUE temp = Qnil; sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); switch( argc ) { case 2: { temp = Vector2_ForceType( args[0] ); sf::Vector2f center; center.x = NUM2DBL( Vector2_GetX( temp ) ); center.y = NUM2DBL( Vector2_GetY( temp ) ); temp = Vector2_ForceType( args[1] ); sf::Vector2f size; size.x = NUM2DBL( Vector2_GetX( temp ) ); size.y = NUM2DBL( Vector2_GetY( temp ) ); object->SetCenter( center ); object->SetSize( size ); break; } case 1: { temp = Rect_ForceType( args[0] ); sf::FloatRect rectangle; rectangle.Left = NUM2DBL( Rect_GetLeft( temp ) ); rectangle.Top = NUM2DBL( Rect_GetTop( temp ) ); rectangle.Width = NUM2DBL( Rect_GetWidth( temp ) ); rectangle.Height = NUM2DBL( Rect_GetHeight( temp ) ); object->Reset( rectangle ); break; } case 0: // Do nothing break; default: rb_raise( rb_eArgError, "Expected 0..2 arguments but was given %d", argc ); } return self; } static VALUE View_InitializeCopy( VALUE self, VALUE aSource ) { sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); sf::View *source = NULL; Data_Get_Struct( aSource, sf::View, source ); *object = *source; } /* call-seq: * view.getCenter() -> vector2 * * Get the center of the view. */ static VALUE View_GetCenter( VALUE self ) { sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); const sf::Vector2f& center = object->GetCenter(); return rb_funcall( globalVector2Class, rb_intern( "new" ), 2, rb_float_new( center.x ), rb_float_new( center.y ) ); } /* call-seq: * view.getRotation() -> float * * Get the current orientation of the view. */ static VALUE View_GetRotation( VALUE self ) { sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); return rb_float_new( object->GetRotation() ); } /* call-seq: * view.getSize() -> vector2 * * Get the size of the view. */ static VALUE View_GetSize( VALUE self ) { sf::View *object = NULL; Data_Get_Struct( self, sf::View, 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 ) ); } /* call-seq: * view.getViewport() -> rectangle * * Get the target viewport rectangle of the view. */ static VALUE View_GetViewport( VALUE self ) { sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); const sf::FloatRect& viewport = object->GetViewport(); return rb_funcall( globalRectClass, rb_intern( "new" ), 4, rb_float_new( viewport.Left ), rb_float_new( viewport.Top ), rb_float_new( viewport.Width ), rb_float_new( viewport.Height ) ); } /* call-seq: * view.move( x, y ) * view.move( offset ) * * Move the view relatively to its current position. */ static VALUE View_Move( int argc, VALUE * args, VALUE self ) { float offsetX = 0; float offsetY = 0; switch( argc ) { case 1: { VALUE temp = Vector2_ForceType( args[0] ); offsetX = NUM2DBL( Vector2_GetX( temp ) ); offsetY = NUM2DBL( Vector2_GetY( temp ) ); break; } case 2: { offsetX = NUM2DBL( args[0] ); offsetY = NUM2DBL( args[1] ); break; } default: rb_raise( rb_eArgError, "Expected 1 or 2 arguments but was given %d", argc ); } sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); object->Move( offsetX, offsetY ); return Qnil; } /* call-seq: * view.reset( rectangle ) * * Reset the view to the given rectangle. * * Note that this function resets the rotation angle to 0. */ static VALUE View_Reset( VALUE self, VALUE aRectangle ) { VALUE temp = Rect_ForceType( aRectangle ); sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); sf::FloatRect rectangle; rectangle.Left = NUM2DBL( Rect_GetLeft( temp ) ); rectangle.Top = NUM2DBL( Rect_GetTop( temp ) ); rectangle.Width = NUM2DBL( Rect_GetWidth( temp ) ); rectangle.Height = NUM2DBL( Rect_GetHeight( temp ) ); object->Reset( rectangle ); return Qnil; } /* call-seq: * view.rotate( angle ) * * Rotate the view relatively to its current orientation. */ static VALUE View_Rotate( VALUE self, VALUE anAngle ) { sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); object->Rotate( NUM2DBL( anAngle ) ); return Qnil; } /* call-seq: * view.setCenter( center ) * view.setCenter( x, y ) * * Set the center of the view. */ static VALUE View_SetCenter( int argc, VALUE * args, VALUE self ) { float x = 0; float y = 0; switch( argc ) { case 1: { VALUE temp = Vector2_ForceType( args[0] ); x = NUM2DBL( Vector2_GetX( temp ) ); y = NUM2DBL( Vector2_GetY( temp ) ); break; } case 2: { x = NUM2DBL( args[0] ); y = NUM2DBL( args[1] ); break; } default: rb_raise( rb_eArgError, "Expected 1 or 2 arguments but was given %d", argc ); } sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); object->SetCenter( x, y ); return Qnil; } /* call-seq: * view.setRotation( angle ) * * Set the orientation of the view. * * The default rotation of a view is 0 degree. */ static VALUE View_SetRotation( VALUE self, VALUE anAngle ) { sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); object->SetRotation( NUM2DBL( anAngle ) ); return Qnil; } /* call-seq: * view.setSize( size ) * view.setSize( width, height ) * * Set the center of the view. */ static VALUE View_SetSize( int argc, VALUE * args, VALUE self ) { float x = 0; float y = 0; switch( argc ) { case 1: { VALUE temp = Vector2_ForceType( args[0] ); x = NUM2DBL( Vector2_GetX( temp ) ); y = NUM2DBL( Vector2_GetY( temp ) ); break; } case 2: { x = NUM2DBL( args[0] ); y = NUM2DBL( args[1] ); break; } default: rb_raise( rb_eArgError, "Expected 1 or 2 arguments but was given %d", argc ); } sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); object->SetSize( x, y ); return Qnil; } /* call-seq: * view.setViewport( rectangle ) * * Set the target viewport. * * The viewport is the rectangle into which the contents of the view are displayed, expressed as a factor * (between 0 and 1) of the size of the RenderTarget to which the view is applied. For example, a view which takes the * left side of the target would be defined with SFML::View.setViewport( [0.0, 0.0, 0.5, 1.0] ). By default, a view has * a viewport which covers the entire target. */ static VALUE View_SetViewport( VALUE self, VALUE aRectangle ) { VALUE temp = Rect_ForceType( aRectangle ); sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); sf::FloatRect viewport; viewport.Left = NUM2DBL( Rect_GetLeft( temp ) ); viewport.Top = NUM2DBL( Rect_GetTop( temp ) ); viewport.Width = NUM2DBL( Rect_GetWidth( temp ) ); viewport.Height = NUM2DBL( Rect_GetHeight( temp ) ); object->SetViewport( viewport ); return Qnil; } /* call-seq: * view.zoom( factor ) * * Resize the view rectangle relatively to its current size. * * Resizing the view simulates a zoom, as the zone displayed on screen grows or shrinks. factor is a multiplier: * * - 1 keeps the size unchanged * - > 1 makes the view bigger (objects appear smaller) * - < 1 makes the view smaller (objects appear bigger) * */ static VALUE View_Zoom( VALUE self, VALUE aFactor ) { sf::View *object = NULL; Data_Get_Struct( self, sf::View, object ); object->Zoom( NUM2DBL( aFactor ) ); return Qnil; } static VALUE View_New( int argc, VALUE *args, VALUE aKlass ) { sf::View *object = new sf::View(); VALUE rbData = Data_Wrap_Struct( aKlass, 0, View_Free, object ); rb_obj_call_init( rbData, argc, args ); return rbData; } void Init_View( void ) { /* SFML namespace which contains the classes of this module. */ VALUE sfml = rb_define_module( "SFML" ); /* 2D camera that defines what region is shown on screen * * sf::View defines a camera in the 2D scene. * * This is a very powerful concept: you can scroll, rotate or zoom the entire scene without altering the way that your * drawable objects are drawn. * * A view is composed of a source rectangle, which defines what part of the 2D scene is shown, and a target viewport, * which defines where the contents of the source rectangle will be displayed on the render target * (window or render-image). * * The viewport allows to map the scene to a custom part of the render target, and can be used for split-screen or * for displaying a minimap, for example. If the source rectangle has not the same size as the viewport, its contents * will be stretched to fit in. * * To apply a view, you have to assign it to the render target. Then, every objects drawn in this render target will * be affected by the view until you use another view. * * Usage example: * * window = SFML::RenderWindow.new * view = SFML::View.new * * # Initialize the view to a rectangle located at (100, 100) and with a size of 400x200 * view.reset( [100.0, 100.0, 400.0, 200.0] ) * * # Rotate it by 45 degrees * view.rotate( 45 ) * * # Set its target viewport to be half of the window * view.viewport = [0.0, 0.0, 0.5, 1.0 ] * * # Apply it * window.view = view * * # Render stuff * window.draw( someSprite ) * * # Set the default view back * window.view = window.defaultView * * # Render stuff not affected by the view * window.draw( someText ) */ globalViewClass = rb_define_class_under( sfml, "View", rb_cObject ); // Class methods rb_define_singleton_method( globalViewClass, "new", View_New, -1 ); // Instance methods rb_define_method( globalViewClass, "initialize", View_Initialize, -1 ); rb_define_method( globalViewClass, "initialize_copy", View_InitializeCopy, 1 ); rb_define_method( globalViewClass, "setCenter", View_SetCenter, -1 ); rb_define_method( globalViewClass, "setSize", View_SetSize, -1 ); rb_define_method( globalViewClass, "setRotation", View_SetRotation, 1 ); rb_define_method( globalViewClass, "setViewport", View_SetViewport, 1 ); rb_define_method( globalViewClass, "reset", View_Reset, 1 ); rb_define_method( globalViewClass, "getCenter", View_GetCenter, 0 ); rb_define_method( globalViewClass, "getSize", View_GetSize, 0 ); rb_define_method( globalViewClass, "getRotation", View_GetRotation, 0 ); rb_define_method( globalViewClass, "getViewport", View_GetViewport, 0 ); rb_define_method( globalViewClass, "move", View_Move, -1 ); rb_define_method( globalViewClass, "rotate", View_Rotate, 1 ); rb_define_method( globalViewClass, "zoom", View_Zoom, 1 ); // Instance Aliases rb_define_alias( globalViewClass, "center=", "setCenter" ); rb_define_alias( globalViewClass, "center", "getCenter" ); rb_define_alias( globalViewClass, "size=", "setSize" ); rb_define_alias( globalViewClass, "size", "getSize" ); rb_define_alias( globalViewClass, "rotation=", "setRotation" ); rb_define_alias( globalViewClass, "rotation", "getRotation" ); rb_define_alias( globalViewClass, "viewport=", "setViewport" ); rb_define_alias( globalViewClass, "viewport", "getViewport" ); }