Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'experimental' of github.com:PerlGameDev/SDL into sdlx_s…

…creen
  • Loading branch information...
commit a4881ab6ea3ea6eb9b07d380c47d5d7abca0cd02 2 parents 95faa03 + b2d3c89
@FROGGS FROGGS authored
Showing with 1,734 additions and 680 deletions.
  1. +1 −1  Build.PL
  2. +21 −0 CHANGELOG
  3. +0 −8 examples/SDLx/SDLx_C_Interface.pl
  4. +0 −1  examples/SDLx/SDLx_Sound.pl
  5. +0 −2  examples/SDLx/SDLx_controller_two_squares.pl
  6. +1 −1  examples/SDLx/SDLx_text.pl
  7. +1 −1  examples/SDLx/SDLx_text_shadow.pl
  8. +1 −1  examples/SDLx/SDLx_text_styles.pl
  9. +1 −1  examples/SDLx/SDLx_text_wordwrap.pl
  10. +1 −1  examples/SDLx/SDLx_text_zoom.pl
  11. +4 −8 examples/SDLx/app.pl
  12. +1 −1  examples/SDLx/music.pl
  13. +1 −3 examples/SDLx/pong.pl
  14. +5 −2 lib/SDL/Constants.pm
  15. +2 −1  lib/SDL/Event.pm
  16. +2 −1  lib/SDL/Events.pm
  17. +2 −0  lib/SDL/GFX/ImageFilter.pm
  18. +291 −175 lib/SDLx/App.pm
  19. +185 −117 lib/SDLx/Controller.pm
  20. +7 −2 lib/SDLx/Music.pm
  21. +48 −7 lib/SDLx/Surface.pm
  22. +30 −0 lib/pods/SDL/Deprecated.pod
  23. +64 −59 lib/pods/SDL/Events.pod
  24. +6 −0 lib/pods/SDL/Surface.pod
  25. +366 −105 lib/pods/SDLx/App.pod
  26. +387 −138 lib/pods/SDLx/Controller.pod
  27. +5 −5 src/Mixer/Channels.xs
  28. +2 −3 t/gfx_imagefilter.t
  29. +9 −5 t/sdlx_app.t
  30. +288 −29 t/sdlx_controller.t
  31. +2 −2 t/sdlx_surface.t
View
2  Build.PL
@@ -625,7 +625,7 @@ my $build = $package->new(
#create_readme => 1, ### make sense only if there is some POD doc in the file specified by dist_version_from
meta_merge => {
resources => {
- bugtracker => 'http://sdlperl.ath.cx/projects/SDLPerl',
+ bugtracker => 'http://github.com/PerlGameDev/SDL/issues',
repository => 'http://github.com/PerlGameDev/SDL'
}
},
View
21 CHANGELOG
@@ -2,6 +2,27 @@ Revision history for Perl extension SDL_perl.
Versioning rule: public releases are even numbers, dev releases are odd. (same like perl dist)
+* 2.537_03 Apr 12 2012
+ - SDLx::App made the docs a lot better [Blaizer]
+ - SDLx::App changed around shortcut names in the constructor [Blaizer]
+ - SDLx::App added and improved parameters of the constructor, see docs [Blaizer]
+ - SDLx::App updated methods resize, title, icon, error, show_cursor, grab_input [Blaizer]
+ - SDLx::App fullscreen method works better [Blaizer]
+ - SDLx::App new init method does our initializing right [Blaizer]
+ - SDLx::App new set_video_mode method does set_video_mode for SDLx::App [Blaizer]
+ - SDLx::App new screen_size method returns the user's screen size [Blaizer]
+ - SDLx::App warp method renamed to warp_cursor, attribute renamed to gl_attribute [Blaizer]
+ - SDLx::App fix to return the user's resolution to normal when a fullscreen app closes [FROGGS]
+ - SDLx::App removed delay method and deprecated get_ticks [Blaizer]
+ - SDLx::Controller removed eoq, its action is on by default and implemented by stop_handler [Blaizer]
+ - SDLx::Controller made the docs a lot better, even proofread them [Blaizer]
+ - SDLx::Controller pause works by stopping the app [Blaizer]
+ - SDLx::Controller added stopped and paused methods to tell what the app is doing [Blaizer]
+ - SDLx::Controller added max_t param, by default slows down apps going at less than 10 FPS [Blaizer]
+ - SDLx::Controller added time and sleep methods to replace get_ticks and delay [Blaizer]
+ - SDLx::Controller added some tests for pausing and events [Blaizer]
+ - SDLx::Controller removed current_time parameter [Blaizer]
+
* 2.537_02 Feb 13 2012
- t/core_cd.t: gnu hurd 0.3 handles devices like cdrom strange (skipping tests) [FROGGS]
- t/sdlx_fps.t: seems better to try to get 5 fps (slow vm's) [FROGGS]
View
8 examples/SDLx/SDLx_C_Interface.pl
@@ -34,14 +34,6 @@
$app->draw_rect( [ 100 - $state->x, $state->y, 2, 2 ], 0xFF0FFF );
};
-#an event handler to exit
-my $event = sub {
- $_[1]->stop if $_[0]->type == SDL_QUIT;
-};
-
-
-$app->add_event_handler($event);
-
#clear the screen
$app->add_show_handler( sub { $app->draw_rect( [ 0, 0, $app->w, $app->h ], 0x000000 ) } );
View
1  examples/SDLx/SDLx_Sound.pl
@@ -44,7 +44,6 @@
# pause or resume on keydown
$app->add_event_handler( sub{
my $e = $_[0];
- $_[1]->stop() if $e->type == SDL_QUIT;
if( $e->type == SDL_KEYDOWN )
{
print "Ai\n";
View
2  examples/SDLx/SDLx_controller_two_squares.pl
@@ -101,8 +101,6 @@ sub on_event {
$ball->{x_vel} += $ball->{vel} if $key == SDLK_LEFT;
$ball->{x_vel} -= $ball->{vel} if $key == SDLK_RIGHT;
- } elsif ( $event->type == SDL_QUIT ) {
- $_[0]->stop;
}
}
View
2  examples/SDLx/SDLx_text.pl
@@ -5,7 +5,7 @@
use SDLx::App;
use SDLx::Text;
-my $app = SDLx::App->new( eoq => 1 );
+my $app = SDLx::App->new();
my $text = SDLx::Text->new;
View
2  examples/SDLx/SDLx_text_shadow.pl
@@ -7,7 +7,7 @@
use SDLx::App;
use SDLx::Text;
-my $app = SDLx::App->new( eoq => 1 );
+my $app = SDLx::App->new();
my $normal = SDLx::Text->new;
my $shadow = SDLx::Text->new( shadow => 1 );
View
2  examples/SDLx/SDLx_text_styles.pl
@@ -5,7 +5,7 @@
use SDLx::App;
use SDLx::Text;
-my $app = SDLx::App->new( eoq => 1 );
+my $app = SDLx::App->new();
my $text = SDLx::Text->new;
View
2  examples/SDLx/SDLx_text_wordwrap.pl
@@ -5,7 +5,7 @@
use SDLx::App;
use SDLx::Text;
-my $app = SDLx::App->new( eoq => 1 );
+my $app = SDLx::App->new();
my $text = SDLx::Text->new( word_wrap => 450 );
View
2  examples/SDLx/SDLx_text_zoom.pl
@@ -7,7 +7,7 @@
use SDLx::App;
use SDLx::Text;
-my $app = SDLx::App->new( eoq => 1, width => 400, height => 100 );
+my $app = SDLx::App->new( width => 400, height => 100 );
my $text = SDLx::Text->new;
View
12 examples/SDLx/app.pl
@@ -7,15 +7,11 @@
height => 480,
);
+sub draw_lines {
+ $app->draw_line( [ rand $app->w, rand $app->h ], [ rand $app->w, rand $app->h ], 0xFFFFFFFF );
+ $app->update();
+}
-
-sub draw_lines { $app->draw_line( [ 0, 0 ], [ rand( $app->w ), rand( $app->h ) ], 0xFFFFFFFF ); $app->update(); }
-
-sub event_handle { my $e = shift; $_[0]->stop if ( $e->type == SDL_QUIT ); }
-
-$app->add_event_handler( \&event_handle );
$app->add_show_handler( \&draw_lines );
$app->run();
-
-
View
2  examples/SDLx/music.pl
@@ -4,4 +4,4 @@
$music->data( sam => "test/data/sample.wav" );
$sam = $music->data("sam");
$music->play($sam);
-while ( $music->playing ) { print "playing\n" }
+while ( $music->playing ) { print "playing\n"; sleep 1; }
View
4 examples/SDLx/pong.pl
@@ -29,7 +29,7 @@
y => 0,
w => 20,
h => 80,
- vel => 250,
+ vel => 130,
y_vel => 0,
};
@@ -143,8 +143,6 @@ sub on_event {
my $key = $event->key_sym;
$paddle->{y_vel} += $paddle->{vel} if $key == SDLK_UP;
$paddle->{y_vel} -= $paddle->{vel} if $key == SDLK_DOWN;
- } elsif ( $event->type == SDL_QUIT ) {
- exit;
}
}
View
7 lib/SDL/Constants.pm
@@ -1031,6 +1031,11 @@ use constant {
}; # SDL::Events/keymod
use constant {
+ SDL_DEFAULT_REPEAT_DELAY => 500,
+ SDL_DEFAULT_REPEAT_INTERVAL => 30,
+}; # SDL::Events/repeat
+
+use constant {
SMOOTHING_OFF => 0,
SMOOTHING_ON => 1,
}; # SDL::GFX/smoothing
@@ -1217,8 +1222,6 @@ use constant {
FPS_LOWER_LIMIT => 1,
FPS_DEFAULT => 30,
SDL_ALL_HOTKEYS => 0xFFFFFFFF,
- SDL_DEFAULT_REPEAT_DELAY => 500,
- SDL_DEFAULT_REPEAT_INTERVAL => 30,
};
use constant {
View
3  lib/SDL/Event.pm
@@ -24,7 +24,8 @@ our %EXPORT_TAGS = (
app => $SDL::Constants::EXPORT_TAGS{'SDL::Events/app'},
button => $SDL::Constants::EXPORT_TAGS{'SDL::Events/button'},
keysym => $SDL::Constants::EXPORT_TAGS{'SDL::Events/keysym'},
- keymod => $SDL::Constants::EXPORT_TAGS{'SDL::Events/keymod'}
+ keymod => $SDL::Constants::EXPORT_TAGS{'SDL::Events/keymod'},
+ repeat => $SDL::Constants::EXPORT_TAGS{'SDL::Events/repeat'}
);
1;
View
3  lib/SDL/Events.pm
@@ -24,7 +24,8 @@ our %EXPORT_TAGS = (
app => $SDL::Constants::EXPORT_TAGS{'SDL::Events/app'},
button => $SDL::Constants::EXPORT_TAGS{'SDL::Events/button'},
keysym => $SDL::Constants::EXPORT_TAGS{'SDL::Events/keysym'},
- keymod => $SDL::Constants::EXPORT_TAGS{'SDL::Events/keymod'}
+ keymod => $SDL::Constants::EXPORT_TAGS{'SDL::Events/keymod'},
+ repeat => $SDL::Constants::EXPORT_TAGS{'SDL::Events/repeat'}
);
1;
View
2  lib/SDL/GFX/ImageFilter.pm
@@ -19,4 +19,6 @@ our %EXPORT_TAGS = (
smoothing => $SDL::Constants::EXPORT_TAGS{'SDL::GFX/smoothing'}
);
+MMX_on();
+
1;
View
466 lib/SDLx/App.pm
@@ -1,234 +1,350 @@
-#!/usr/bin/env perl
-#
-# App.pm
-#
-
package SDLx::App;
use strict;
use warnings;
-use Carp;
-use SDL;
-
-use SDL::Rect;
-use SDL::Video;
-use SDL::Event;
-use SDL::Events;
-use SDL::Surface;
-use SDL::PixelFormat;
-use SDL::VideoInfo;
-use SDLx::Surface;
-use Data::Dumper;
-use Scalar::Util 'refaddr';
+
+# SDL modules actually used here
+use SDL ();
+use SDL::Video ();
+use SDL::Mouse ();
+use SDL::Event ();
+use SDL::Surface ();
+use SDL::VideoInfo ();
+use SDLx::Validate ();
use base qw/SDLx::Surface SDLx::Controller/;
-my $screen_w;
-my $screen_h;
-my $screen_d;
+# SDL modules used for other reasons
+# Please verify their usefulness here
+use SDL::Rect ();
+use SDL::Events ();
+use SDL::PixelFormat ();
+
+use Carp ();
+use Scalar::Util qw/refaddr/;
+
+my %_stash;
+my $_screen_w;
+my $_screen_h;
+my $_screen_d;
+
+$SDLx::App::USING_OPENGL = 0;
sub new {
- my $proto = shift;
- my $class = ref($proto) || $proto;
- my %options = @_;
+ my $class = shift;
+
+ my %o = @_;
+
+ # undef is not a valid input
+ my $w = defined $o{width} ? $o{width} : defined $o{w} ? $o{w} : 640;
+ my $h = defined $o{height} ? $o{height} : defined $o{h} ? $o{h} : 480;
+ my $d = defined $o{depth} ? $o{depth} : defined $o{d} ? $o{d} : undef;
+ my $f = defined $o{flags} ? $o{flags} : defined $o{f} ? $o{f} : 0;
+ my $pos = defined $o{position} ? $o{position} : defined $o{pos} ? $o{pos} : undef;
+ my $ico = $o{icon};
+
+ # undef is a valid input
+ my $t = $o{title};
+ my $it = $o{icon_title};
+ my $init = exists $o{initialize} ? $o{initialize} : $o{init};
+ my $s = exists $o{stash} ? $o{stash} : {};
+ my $icc = $o{icon_color_key};
+
+ # boolean
+ my $sw = $o{software_surface} || $o{sw_surface} || $o{sw};
+ my $hw = $o{hardware_surface} || $o{hw_surface} || $o{hw};
+ my $ab = $o{asynchronous_blit} || $o{async_blit};
+ my $af = $o{any_format};
+ my $hwp = $o{hardware_palette} || $o{hw_palette};
+ my $db = $o{double_buffer} || $o{double_buf} || $o{dbl_buf};
+ my $fs = $o{full_screen} || $o{fullscreen} || $o{full};
+ my $gl = $o{open_gl} || $o{opengl} || $o{gl};
+ my $rs = $o{resizable} || $o{resizeable}; # it's a hard word to spell :-)
+ my $nf = $o{no_frame};
+ my $ncur = $o{hide_cursor} || $o{no_cursor};
+ my $cen = $o{centered} || $o{center};
+ my $gi = $o{grab_input};
+ my $nc = $o{no_controller};
+
+ unless ( defined $d ) {
+ # specify SDL_ANYFORMAT flag if depth isn't defined
+ $d = 32;
+ $af = 1;
+ }
- unless($screen_w && $screen_h && $screen_d) {
+ # used to say unless no_init here. I don't think we need it anymore
+ if( !defined $init ) {
+ SDLx::App->init( SDL::SDL_INIT_EVERYTHING );
+ }
+ else {
+ if( ref $init ) {
+ push @$init, "video";
+ }
+ else {
+ $init |= SDL::SDL_INIT_VIDEO
+ }
+ SDLx::App->init( $init );
+ }
+
+ # keep the screen's original res so we can set the app to that when we're done
+ unless(defined $_screen_w && defined $_screen_h && defined $_screen_d) {
my $video_info = SDL::Video::get_video_info();
if($video_info) {
- $screen_w = $video_info->current_w;
- $screen_h = $video_info->current_h;
- $screen_d = $video_info->vfmt->BitsPerPixel;
+ $_screen_w = $video_info->current_w;
+ $_screen_h = $video_info->current_h;
+ $_screen_d = $video_info->vfmt->BitsPerPixel;
}
}
- # SDL_INIT_VIDEO() is 0, so check defined instead of truth.
- unless ( exists( $options{noinit} ) ) # we shouldn't do init always
- {
- my $init =
- defined $options{init}
- ? $options{init}
- : SDL::SDL_INIT_EVERYTHING;
-
- SDL::init($init);
- }
-
- my $t = $options{title} || $options{t} || $0;
- my $it = $options{icon_title} || $options{it} || $t;
- my $ic = $options{icon} || $options{i} || "";
- my $w = $options{width} || $options{w} || 800;
- my $h = $options{height} || $options{h} || 600;
- my $d = $options{depth} || $options{d} || 16;
- my $f = $options{flags} || $options{f} || SDL::Video::SDL_ANYFORMAT;
- my $r = $options{red_size} || $options{r} || 5;
- my $g = $options{green_size} || $options{g} || 5;
- my $b = $options{blue_size} || $options{b} || 5;
- my $a = $options{alpha_size} || $options{a} || 0;
- my $ras = $options{red_accum_size} || $options{ras} || 0;
- my $gas = $options{green_accum_size} || $options{gas} || 0;
- my $bas = $options{blue_accum_size} || $options{bas} || 0;
- my $aas = $options{alpha_accum_size} || $options{aas} || 0;
- my $db = $options{double_buffer} || $options{db} || 0;
-
- my $bs = $options{buffer_size} || $options{bs} || 0;
- my $st = $options{stencil_size} || $options{st} || 0;
- my $async = $options{asyncblit} || 0;
-
- $f |= SDL::Video::SDL_OPENGL if ( $options{gl} || $options{opengl} );
- $f |= SDL::Video::SDL_FULLSCREEN
- if ( $options{fullscreen} || $options{full} );
- $f |= SDL::Video::SDL_RESIZABLE if ( $options{resizeable} );
- $f |= SDL::Video::SDL_DOUBLEBUF if ($db);
- $f |= SDL::Video::SDL_ASYNCBLIT if ($async);
-
- if ( $f & SDL::Video::SDL_OPENGL ) {
+ $f |= SDL::Video::SDL_SWSURFACE if $sw;
+ $f |= SDL::Video::SDL_HWSURFACE if $hw;
+ $f |= SDL::Video::SDL_ASYNCBLIT if $ab;
+ $f |= SDL::Video::SDL_ANYFORMAT if $af;
+ $f |= SDL::Video::SDL_HWPALETTE if $hwp;
+ $f |= SDL::Video::SDL_DOUBLEBUF if $db;
+ $f |= SDL::Video::SDL_FULLSCREEN if $fs;
+ $f |= SDL::Video::SDL_OPENGL if $gl;
+ $f |= SDL::Video::SDL_RESIZABLE if $rs;
+ $f |= SDL::Video::SDL_NOFRAME if $nf;
+
+ # we'll let SDL decide which takes priority and set both if both are specified
+ $ENV{SDL_VIDEO_CENTERED} = $cen if $cen;
+ $ENV{SDL_VIDEO_WINDOW_POS} = $pos if $pos;
+
+ if ( $gl ) {
$SDLx::App::USING_OPENGL = 1;
- SDL::Video::GL_set_attribute( SDL::Constants::SDL_GL_RED_SIZE(), $r )
- if ($r);
- SDL::Video::GL_set_attribute( SDL::Constants::SDL_GL_GREEN_SIZE(), $g )
- if ($g);
- SDL::Video::GL_set_attribute( SDL::Constants::SDL_GL_BLUE_SIZE(), $b )
- if ($b);
- SDL::Video::GL_set_attribute( SDL::Constants::SDL_GL_ALPHA_SIZE(), $a )
- if ($a);
-
- SDL::Video::GL_set_attribute(
- SDL::Constants::SDL_GL_RED_ACCUM_SIZE(),
- $ras
- ) if ($ras);
- SDL::Video::GL_set_attribute(
- SDL::Constants::SDL_GL_GREEN_ACCUM_SIZE(),
- $gas
- ) if ($gas);
- SDL::Video::GL_set_attribute(
- SDL::Constants::SDL_GL_BLUE_ACCUM_SIZE(),
- $bas
- ) if ($bas);
- SDL::Video::GL_set_attribute(
- SDL::Constants::SDL_GL_ALPHA_ACCUM_SIZE(),
- $aas
- ) if ($aas);
-
- SDL::Video::GL_set_attribute(
- SDL::Constants::SDL_GL_DOUBLEBUFFER(),
- $db
- ) if ($db);
- SDL::Video::GL_set_attribute(
- SDL::Constants::SDL_GL_BUFFER_SIZE(),
- $bs
- ) if ($bs);
- SDL::Video::GL_set_attribute( SDL::Constants::SDL_GL_DEPTH_SIZE(), $d );
- } else {
- $SDLx::App::USING_OPENGL = 0;
+
+ my $r = defined $o{gl_red_size} ? $o{gl_red_size} : defined $o{gl_red} ? $o{gl_red} : 5;
+ my $g = defined $o{gl_green_size} ? $o{gl_green_size} : defined $o{gl_green} ? $o{gl_green} : 5;
+ my $b = defined $o{gl_blue_size} ? $o{gl_blue_size} : defined $o{gl_blue} ? $o{gl_blue} : 5;
+ my $a = defined $o{gl_alpha_size} ? $o{gl_alpha_size} : defined $o{gl_alpha} ? $o{gl_alpha} : undef;
+ my $ra = defined $o{gl_accum_red_size} ? $o{gl_accum_red_size} : defined $o{gl_accum_red} ? $o{gl_accum_red} : undef;
+ my $ga = defined $o{gl_accum_green_size} ? $o{gl_accum_green_size} : defined $o{gl_accum_green} ? $o{gl_accum_green} : undef;
+ my $ba = defined $o{gl_accum_blue_size} ? $o{gl_accum_blue_size} : defined $o{gl_accum_blue} ? $o{gl_accum_blue} : undef;
+ my $aa = defined $o{gl_accum_alpha_size} ? $o{gl_accum_alpha_size} : defined $o{gl_accum_alpha} ? $o{gl_accum_alpha} : undef;
+ my $bs = defined $o{gl_buffer_size} ? $o{gl_buffer_size} : defined $o{gl_buffer} ? $o{gl_buffer} : undef;
+ my $ss = defined $o{gl_stencil_size} ? $o{gl_stencil_size} : defined $o{gl_stencil} ? $o{gl_stencil} : undef;
+ my $msb = defined $o{gl_multi_sample_buffers} ? $o{gl_multi_sample_buffers} : undef;
+ my $mss = defined $o{gl_multi_sample_samples} ? $o{gl_multi_sample_samples} : undef;
+
+ # boolean
+ my $s = $o{gl_stereo};
+ my $sc = $o{gl_swap_control};
+ my $av = $o{gl_accelerated_visual};
+
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_RED_SIZE, $r ) if defined $r;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_GREEN_SIZE, $g ) if defined $g;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_BLUE_SIZE, $b ) if defined $b;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_ALPHA_SIZE, $a ) if defined $a;
+
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_ACCUM_RED_SIZE, $ra ) if defined $ra;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_ACCUM_GREEN_SIZE, $ga ) if defined $ga;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_ACCUM_BLUE_SIZE, $ba ) if defined $ba;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_ACCUM_ALPHA_SIZE, $aa ) if defined $aa;
+
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_BUFFER_SIZE, $bs ) if defined $bs;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_DOUBLEBUFFER, $db ) if defined $db;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_DEPTH_SIZE, $d );
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_STENCIL_SIZE, $ss ) if defined $ss;
+
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_STEREO, $s ) if defined $s;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_MULTISAMPLEBUFFERS, $msb ) if defined $msb;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_MULTISAMPLESAMPLES, $mss ) if defined $mss;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_SWAP_CONTROL, $sc ) if defined $sc;
+ SDL::Video::GL_set_attribute( SDL::Video::SDL_GL_ACCELERATED_VISUAL, $av ) if defined $av;
}
+ # icon must be set before set_video_mode
+ SDLx::App->icon( $ico, $icc ) if defined $ico;
+
+ my $self = $class->set_video_mode( $w, $h, $d, $f );
+ $self->SDLx::Controller::new( %o ) unless $nc;
+
+ $t = defined $it ? $it : $0 unless defined $t;
+ $it = $t unless defined $it;
+ $self->title( $t, $it );
+
+ $self->show_cursor( 0 ) if $ncur;
+ $self->grab_input( $gi ) if $gi;
+ $self->stash = $s;
+
+ $self;
+}
+
+sub set_video_mode {
+ my ( $self, $w, $h, $d, $f ) = @_;
my $surface = SDL::Video::set_video_mode( $w, $h, $d, $f )
- or Carp::confess SDL::get_error();
- $options{surface} = $surface;
+ or Carp::confess( "set_video_mode failed: ", SDL::get_error() );
+ $surface = SDLx::Surface->new( surface => $surface );
+
+ # if we already have an app
+ if( ref $self ) {
+ return $self;
+ }
+ return bless $surface, $self;
+}
- my $self = SDLx::Surface->new(%options);
+sub DESTROY {
+ my ( $self ) = @_;
- if ( $ic and -e $ic ) {
- my $icon = SDL::Video::load_BMP($ic);
- SDL::Video::wm_set_icon($icon);
+ # set original screen size when app ends
+ if(defined $_screen_w && defined $_screen_h && defined $_screen_d) {
+ SDL::Video::set_video_mode( $_screen_w, $_screen_h, $_screen_d, $self->flags );
}
- SDL::Video::wm_set_caption( $t, $it );
- $self = $self->SDLx::Controller::new(%options);
- bless $self, $class;
+ my $ref = refaddr($self);
+ delete $_stash{ $ref };
+}
- return $self;
+sub stash :lvalue {
+ $_stash{ refaddr( $_[0] ) };
+}
+
+sub init {
+ my ( undef, $init ) = @_;
+
+ if ( ref $init ) {
+ # make a hash with keys of the values in the init array
+ my %init = map { $_ => 1 } @$init;
+ undef $init;
+
+ $init |= SDL::SDL_INIT_TIMER if $init{timer};
+ $init |= SDL::SDL_INIT_AUDIO if $init{audio};
+ $init |= SDL::SDL_INIT_VIDEO if $init{video};
+ $init |= SDL::SDL_INIT_CDROM if $init{cd_rom} || $init{cdrom};
+ $init |= SDL::SDL_INIT_JOYSTICK if $init{joystick};
+ $init |= SDL::SDL_INIT_EVERYTHING if $init{everything} || $init{all};
+ $init |= SDL::SDL_INIT_NOPARACHUTE if $init{no_parachute};
+ $init |= SDL::SDL_INIT_EVENTTHREAD if $init{event_thread};
+ }
+
+ # if anything is already inited, only init specified extra subsystems
+ if ( SDL::was_init( SDL::SDL_INIT_EVERYTHING ) ) {
+ SDL::init_sub_system( $init )
+ and Carp::cluck( "SDL init_sub_system failed: ", SDL::get_error() );
+ }
+ else {
+ SDL::init( $init )
+ and Carp::confess( "SDL init failed: ", SDL::get_error() );
+ }
+}
+
+sub screen_size {
+ SDLx::App->init( SDL::SDL_INIT_VIDEO );
+
+ my $video_info = SDL::Video::get_video_info();
+
+ return( $video_info->current_w, $video_info->current_h, $video_info->vfmt->BitsPerPixel );
}
sub resize {
my ( $self, $w, $h ) = @_;
- my $flags = $self->flags;
- if ( $flags & SDL::Video::SDL_RESIZABLE ) {
- my $bpp = $self->format->BitsPerPixel;
- $self = SDL::Video::set_video_mode( $w, $h, $bpp, $flags )
- or die "SDL cannot set video:" . SDL::get_error;
- } else {
- die "Application surface not resizable";
- }
+
+ my $d = $self->format->BitsPerPixel;
+ my $f = $self->flags;
+
+ $self->set_video_mode( $w, $h, $d, $f );
}
sub title {
- my $self = shift;
- my ( $title, $icon );
- if (@_) {
- $title = shift;
- $icon = shift || $title;
- SDL::Video::wm_set_caption( $title, $icon );
+ my ( undef, $title, $icon_title ) = @_;
+ if ( @_ > 1 ) {
+ my ($t, $it) = SDL::Video::wm_get_caption;
+ $title = $t unless defined $title;
+ $icon_title = $it unless defined $icon_title;
+ return SDL::Video::wm_set_caption( $title, $icon_title );
}
- return SDL::Video::wm_get_caption();
+ SDL::Video::wm_get_caption;
}
-sub delay {
- my $self = shift;
- my $delay = shift;
- SDL::delay($delay);
+sub icon {
+ my ( undef, $icon, $color ) = @_;
+ SDLx::App->init( SDL::SDL_INIT_VIDEO );
+ unless( UNIVERSAL::isa( $icon, "SDL::Surface" ) ) {
+ $icon = SDL::Video::load_BMP( $icon );
+ $icon or Carp::confess( "Could not load_BMP icon '$icon': ", SDL::get_error() );
+ }
+ if( defined $color ) {
+ $color = SDLx::Validate::map_rgb( $color, $icon->format );
+ SDL::Video::set_color_key( $icon, SDL::Video::SDL_SRCCOLORKEY, $color );
+ }
+ SDL::Video::wm_set_icon( $icon );
}
-sub ticks {
- return SDL::get_ticks();
+sub error {
+ shift;
+ if ( @_ == 1 and !defined $_[0] ) {
+ return SDL::clear_error;
+ }
+ if ( @_ ) {
+ return SDL::set_error_real( @_ );
+ }
+ SDL::get_error;
}
-sub error {
- return SDL::get_error();
+sub warp_cursor {
+ my ( undef, $x, $y ) = @_;
+ SDL::Mouse::warp_mouse( $x || 0, $y || 0 );
}
-sub warp {
- my $self = shift;
- SDL::Mouse::warp_mouse(@_);
+sub show_cursor {
+ my ( undef, $show ) = @_;
+ if ( @_ > 1 ) {
+ return SDL::Mouse::show_cursor( SDL::Event::SDL_ENABLE ) if $show and $show ne SDL::Event::SDL_QUERY;
+ return SDL::Mouse::show_cursor( SDL::Event::SDL_DISABLE ) unless $show;
+ }
+ SDL::Mouse::show_cursor( SDL::Event::SDL_QUERY );
}
sub fullscreen {
- my $self = shift;
- SDL::Video::wm_toggle_fullscreen($self);
+ my ( $self ) = @_;
+ return 1 if SDL::Video::wm_toggle_fullscreen( $self );
+
+ # fallback to doing it with set_video_mode()
+ my $d = $self->format->BitsPerPixel;
+ my $f = $self->flags;
+
+ eval { $self->set_video_mode( 0, 0, $d, $f ^ SDL::Video::SDL_FULLSCREEN ) };
+ return 1 unless $@;
+
+ # failed going fullscreen, let's revert back
+ $self->set_video_mode( 0, 0, $d, $f );
+
+ # report failure to go fullscreen
+ return 0;
}
sub iconify {
- my $self = shift;
- SDL::Video::wm_iconify_window();
+ SDL::Video::wm_iconify_window;
}
sub grab_input {
- my ( $self, $mode ) = @_;
- SDL::Video::wm_grab_input($mode);
-}
-
-sub sync {
- my $self = shift;
- if ($SDLx::App::USING_OPENGL) {
- SDL::Video::GL_swap_buffers();
- } else {
- $self->flip();
+ my ( undef, $grab ) = @_;
+ if (@_ > 1) {
+ return SDL::Video::wm_grab_input( SDL::Video::SDL_GRAB_ON ) if $grab and $grab ne SDL::Video::SDL_GRAB_QUERY;
+ return SDL::Video::wm_grab_input( SDL::Video::SDL_GRAB_OFF ) unless $grab;
}
+ SDL::Video::wm_grab_input( SDL::Video::SDL_GRAB_QUERY );
}
-sub attribute {
- my ( $self, $mode, $value ) = @_;
- return undef unless ($SDLx::App::USING_OPENGL);
- if ( defined $value ) {
- SDL::Video::GL_set_attribute( $mode, $value );
+sub sync {
+ my ( $self ) = @_;
+ if ( $SDLx::App::USING_OPENGL ) {
+ return SDL::Video::GL_swap_buffers;
}
- my $returns = SDL::Video::GL_get_attribute($mode);
- Carp::confess "SDLx::App::attribute failed to get GL attribute"
- if ( $$returns[0] < 0 );
- $$returns[1];
+ SDL::Video::flip( $self );
}
+sub gl_attribute {
+ my ( undef, $mode, $value ) = @_;
-
-my %_stash;
-sub stash :lvalue{
- my $ref = refaddr($_[0]);
- $_stash{ $ref } = {} unless $_stash{ $ref };
- return $_stash{ $ref }
-}
-
-sub DESTROY {
- if($screen_w && $screen_h && $screen_d) {
- SDL::Video::set_video_mode( $screen_w, $screen_h, $screen_d, SDL_ANYFORMAT );
+ return unless $SDLx::App::USING_OPENGL;
+ if ( @_ > 2 ) {
+ return SDL::Video::GL_set_attribute( $mode, $value );
}
+ my $returns = SDL::Video::GL_get_attribute( $mode );
+ Carp::cluck( "SDL::Video::GL_get_attribute failed to get GL attribute" )
+ if $returns->[0] < 0;
+ $returns->[1];
}
1;
View
302 lib/SDLx/Controller.pm
@@ -1,180 +1,215 @@
package SDLx::Controller;
use strict;
use warnings;
-use Carp;
-use Time::HiRes;
-use SDL;
-use SDL::Event;
-use SDL::Events;
-use SDL::Video;
+use Carp ();
+use Time::HiRes ();
+use SDL ();
+use SDL::Event ();
+use SDL::Events ();
+use SDL::Video ();
use SDLx::Controller::Interface;
use SDLx::Controller::State;
use Scalar::Util 'refaddr';
-# inside out, so this can work as the superclass of another
-# SDL::Surface subclass
+# inside out, so this can work as the superclass of another class
my %_dt;
my %_min_t;
-my %_current_time;
+my %_max_t;
my %_stop;
my %_event;
my %_event_handlers;
my %_move_handlers;
my %_show_handlers;
-my %_sleep_cycle;
-my %_eoq;
+my %_delay;
my %_paused;
+my %_time;
+my %_stop_handler;
sub new {
my ($self, %args) = @_;
- if(ref $self) {
- bless $self, ref $self;
- }
- else {
+
+ # if $self is blessed then it has to isa controller, so let's not even bless it to this class
+ unless(ref $self) {
my $a;
$self = bless \$a, $self;
}
my $ref = refaddr $self;
- $_dt{ $ref } = defined $args{dt} ? $args{dt} : 0.1;
- $_min_t{ $ref } = defined $args{min_t} ? $args{min_t} : 1 / 60;
-# $_current_time{ $ref } = $args{current_time} || 0; #no point
- $_stop{ $ref } = $args{stop};
- $_event{ $ref } = $args{event} || SDL::Event->new();
- $_event_handlers{ $ref } = $args{event_handlers} || [];
- $_move_handlers{ $ref } = $args{move_handlers} || [];
- $_show_handlers{ $ref } = $args{show_handlers} || [];
- $_sleep_cycle{ $ref } = $args{delay};
- $_eoq{$ref} = $args{exit_on_quit} || $args{eoq} || 0;
-# $_paused{ $ref } = $args{paused}; #read only
+ $_dt{ $ref } = defined $args{dt} ? $args{dt} : 0.1;
+ $_min_t{ $ref } = defined $args{min_t} ? $args{min_t} : 1 / 60;
+ $_max_t{ $ref } = defined $args{max_t} ? $args{max_t} : 0.1;
+ $_stop{ $ref } = 1;
+ $_event{ $ref } = $args{event} || SDL::Event->new();
+ $_event_handlers{ $ref } = $args{event_handlers} || [];
+ $_move_handlers{ $ref } = $args{move_handlers} || [];
+ $_show_handlers{ $ref } = $args{show_handlers} || [];
+ $_delay{ $ref } = defined $args{delay} && $args{delay} >= 1 ? $args{delay} / 1000 : $args{delay} || 0; # accepts seconds or ticks
+# $_paused{ $ref } = undef;
+ $_time{ $ref } = $args{time} || 0;
+ $_stop_handler{ $ref } = exists $args{stop_handler} ? $args{stop_handler} : \&default_stop_handler;
return $self;
}
-
-sub delay {
- my $self = shift;
- my $delay = shift;
- my $ref = refaddr $self;
-
- $_sleep_cycle{ $ref } = $delay if $delay;
- return $self;
-}
-
sub DESTROY {
my $self = shift;
my $ref = refaddr $self;
- delete $_dt{ $ref};
- delete $_min_t{ $ref};
- delete $_current_time{ $ref};
- delete $_stop{ $ref};
- delete $_event{ $ref};
- delete $_event_handlers{ $ref};
- delete $_move_handlers{ $ref};
- delete $_show_handlers{ $ref};
- delete $_sleep_cycle { $ref };
- delete $_eoq{$ref};
- delete $_paused{$ref};
+ delete $_dt{ $ref };
+ delete $_min_t{ $ref };
+ delete $_max_t{ $ref };
+ delete $_stop{ $ref };
+ delete $_event{ $ref };
+ delete $_event_handlers{ $ref };
+ delete $_move_handlers{ $ref };
+ delete $_show_handlers{ $ref };
+ delete $_delay { $ref };
+ delete $_paused{ $ref };
+ delete $_time{ $ref };
+ delete $_stop_handler{ $ref };
}
sub run {
- my ($self) = @_;
- my $ref = refaddr $self;
- my $dt = $_dt{ $ref };
- my $min_t = $_min_t{ $ref };
- my $t = 0.0;
+ my ($self) = @_;
+ my $ref = refaddr $self;
+ my $dt = $_dt{ $ref };
+ my $delay = $_delay{ $ref };
- #Allows us to do stop and run
- $_stop{ $ref } = 0;
+ # these should never change
+ my $event_handlers = $_event_handlers{ $ref };
+ my $move_handlers = $_move_handlers{ $ref };
+ my $show_handlers = $_show_handlers{ $ref };
- $_current_time{ $ref } = Time::HiRes::time;
- while ( !$_stop{ $ref } ) {
- $self->_event($ref);
+ # alows us to do stop and run
+ delete $_stop{ $ref };
+ delete $_paused{ $ref };
+
+ my $current_time = Time::HiRes::time;
+ Time::HiRes::sleep( $delay ) if $delay;
+ while ( !$_stop{ $ref } ) {
my $new_time = Time::HiRes::time;
- my $delta_time = $new_time - $_current_time{ $ref };
- next if $delta_time < $min_t;
- $_current_time{ $ref} = $new_time;
+ my $delta_time = $new_time - $current_time;
+ if( $delta_time < $_min_t{ $ref } ) {
+ Time::HiRes::sleep( 0.001 ); # sleep at least a millisecond
+ redo;
+ }
+ $current_time = $new_time;
+ $delta_time = $_max_t{ $ref } if $delta_time > $_max_t{ $ref };
my $delta_copy = $delta_time;
+ my $time_ref = \$_time{ $ref };
+
+ $self->_event( $ref, $event_handlers );
while ( $delta_copy > $dt ) {
- $self->_move( $ref, 1, $t ); #a full move
+ $self->_move( $move_handlers, 1, $$time_ref ); # a full move
$delta_copy -= $dt;
- $t += $dt;
+ $$time_ref += $dt;
}
my $step = $delta_copy / $dt;
- $self->_move( $ref, $step, $t ); #a partial move
- $t += $dt * $step;
+ $self->_move( $move_handlers, $step, $$time_ref ); # a partial move
+ $$time_ref += $dt * $step;
- $self->_show( $ref, $delta_time );
+ $self->_show( $show_handlers, $delta_time );
- $dt = $_dt{ $ref}; #these can change
- $min_t = $_min_t{ $ref}; #during the cycle
- SDL::delay( $_sleep_cycle{ $ref } ) if $_sleep_cycle{ $ref };
+ Time::HiRes::sleep( $delay ) if $delay;
+
+ # these can change during the cycle
+ $dt = $_dt{ $ref };
+ $delay = $_delay{ $ref };
}
+ # pause works by stopping the app and running it again
+ if( $_paused{ $ref } ) {
+ delete $_stop{ $ref };
+
+ $self->_pause($ref);
+
+ delete $_paused{ $ref };
+
+ # exit out of this sub before going back in so we don't recurse deeper and deeper
+ goto $self->can('run')
+ unless $_stop{ $ref };
+ }
}
-sub exit_on_quit {
- my ($self, $value) = @_;
+sub stop {
+ my $ref = refaddr $_[0];
- my $ref = refaddr $self;
- if (defined $value) {
- $_eoq{$ref} = $value;
- }
+ $_stop{ $ref } = 1;
- return $_eoq{$ref};
+ # if we're going to stop we don't want to pause
+ delete $_paused{ $ref };
+}
+sub stopped {
+ # returns true if the app is stopped or about to stop
+ $_stop{ refaddr $_[0] };
}
-*eoq = \&exit_on_quit; # alias
+sub _pause {
+ my ($self, $ref) = @_;
+ my $event = $_event{ $ref };
+ my $stop_handler = $_stop_handler{ $ref };
+ my $callback = $_paused{ $ref };
+
+ do {
+ SDL::Events::pump_events(); # don't know if we need this
+ SDL::Events::wait_event( $event ) or Carp::confess("pause failed waiting for an event");
+ $stop_handler->( $event, $self ) if $stop_handler;
+ }
+ until
+ $_stop{ $ref } # stop set by stop_handler
+ or !$callback or $callback->( $event, $self )
+ or $_stop{ $ref } # stop set by callback
+ ;
+}
sub pause {
my ($self, $callback) = @_;
my $ref = refaddr $self;
- $callback ||= sub {1};
- my $event = SDL::Event->new();
- $_paused{ $ref} = 1;
- while(1) {
- SDL::Events::wait_event($event) or Carp::confess("pause failed waiting for an event");
- if($callback->($event, $self)) {
- $_current_time{ $ref} = Time::HiRes::time; #so run doesn't catch up with the time paused
- last;
- }
- }
- delete $_paused{ $ref};
+
+ # if we're going to stop we don't want to pause
+ return if !$_paused{ $ref } and $_stop{ $ref };
+
+ $_stop{ $ref } = 1;
+ $_paused{ $ref } = $callback;
+}
+sub paused {
+ # returns the callback (always true) if the app is paused or about to pause
+ $_paused{ refaddr $_[0] };
}
sub _event {
- my ($self, $ref) = @_;
+ my ($self, $ref, $event_handlers) = @_;
+ my $stop_handler = $_stop_handler{ $ref };
+ my $event = $_event{ $ref };
+
SDL::Events::pump_events();
- while ( SDL::Events::poll_event( $_event{ $ref} ) ) {
- $self->_exit_on_quit( $_event{ $ref} ) if $_eoq{$ref};
- foreach my $event_handler ( @{ $_event_handlers{ $ref} } ) {
+ while ( SDL::Events::poll_event( $event ) ) {
+ $stop_handler->( $event, $self ) if $stop_handler;
+ foreach my $event_handler ( @$event_handlers ) {
next unless $event_handler;
- $event_handler->( $_event{ $ref}, $self );
+ $event_handler->( $event, $self );
}
}
}
sub _move {
- my ($self, $ref, $move_portion, $t) = @_;
- foreach my $move_handler ( @{ $_move_handlers{ $ref} } ) {
+ my ($self, $move_handlers, $move_portion, $t) = @_;
+ foreach my $move_handler ( @$move_handlers ) {
next unless $move_handler;
$move_handler->( $move_portion, $self, $t );
}
}
sub _show {
- my ($self, $ref, $delta_ticks) = @_;
- foreach my $show_handler ( @{ $_show_handlers{ $ref} } ) {
+ my ($self, $show_handlers, $delta_ticks) = @_;
+ foreach my $show_handler ( @$show_handlers ) {
next unless $show_handler;
$show_handler->( $delta_ticks, $self );
}
}
-sub stop { $_stop{ refaddr $_[0] } = 1 }
-
sub _add_handler {
my ( $arr_ref, $handler ) = @_;
push @{$arr_ref}, $handler;
@@ -183,27 +218,27 @@ sub _add_handler {
sub add_move_handler {
my $ref = refaddr $_[0];
- return _add_handler( $_move_handlers{ $ref}, $_[1] );
+ return _add_handler( $_move_handlers{ $ref }, $_[1] );
}
sub add_event_handler {
my $ref = refaddr $_[0];
Carp::confess 'SDLx::App or a Display (SDL::Video::get_video_mode) must be made'
unless SDL::Video::get_video_surface();
- return _add_handler( $_event_handlers{ $ref}, $_[1] );
+ return _add_handler( $_event_handlers{ $ref }, $_[1] );
}
sub add_show_handler {
my $ref = refaddr $_[0];
- return _add_handler( $_show_handlers{ $ref}, $_[1] );
+ return _add_handler( $_show_handlers{ $ref }, $_[1] );
}
sub _remove_handler {
my ( $arr_ref, $id ) = @_;
if ( ref $id ) {
($id) = grep {
- $id eq $arr_ref->[$_]
- } 0..$#{$arr_ref};
+ $id eq $arr_ref->[$_]
+ } 0..$#{$arr_ref};
if ( !defined $id ) {
Carp::cluck("$id is not currently a handler of this type");
@@ -254,39 +289,72 @@ sub show_handlers { $_show_handlers{ refaddr $_[0] } }
sub dt {
my ($self, $arg) = @_;
my $ref = refaddr $self;
- $_dt{ $ref} = $arg if defined $arg;
+ $_dt{ $ref } = $arg if defined $arg;
- $_dt{ $ref};
+ $_dt{ $ref };
}
sub min_t {
my ($self, $arg) = @_;
my $ref = refaddr $self;
- $_min_t{ $ref} = $arg if defined $arg;
+ $_min_t{ $ref } = $arg if defined $arg;
- $_min_t{ $ref};
+ $_min_t{ $ref };
}
-sub current_time {
+sub max_t {
my ($self, $arg) = @_;
my $ref = refaddr $self;
- $_current_time{ $ref} = $arg if defined $arg;
+ $_max_t{ $ref } = $arg if defined $arg;
- $_current_time{ $ref};
+ $_max_t{ $ref };
}
-sub paused {
- $_paused{ refaddr $_[0]};
+sub delay {
+ my ($self, $arg) = @_;
+ my $ref = refaddr $self;
+ $_delay{ $ref } = $arg if defined $arg;
+
+ $_delay{ $ref };
}
-sub _exit_on_quit {
- my ($self, $event) = @_;
+sub stop_handler {
+ my ($self, $arg) = @_;
+ my $ref = refaddr $self;
+ $_stop_handler{ $ref } = $arg if @_ > 1;
- $self->stop() if $event->type == SDL_QUIT;
+ $_stop_handler{ $ref };
}
-1;
+sub default_stop_handler {
+ my ($event, $self) = @_;
-__END__
+ $self->stop() if $event->type == SDL::Events::SDL_QUIT;
+}
+sub event {
+ my ($self, $arg) = @_;
+ my $ref = refaddr $self;
+ $_event{ $ref } = $arg if defined $arg;
+
+ $_event{ $ref };
+}
+
+# replacements for SDLx::App::get_ticks() and SDLx::App::delay()
+sub time {
+ my ($self, $arg) = @_;
+ my $ref = refaddr $self;
+ $_time{ $ref } = $arg if defined $arg;
+ $_time{ $ref };
+}
+sub sleep {
+ return Time::HiRes::sleep( $_[1] );
+}
+
+# deprecated
+sub ticks {
+ return SDL::get_ticks();
+}
+
+1;
View
9 lib/SDLx/Music.pm
@@ -45,7 +45,8 @@ sub new {
sub data {
my $self = shift;
- return if $#_ < 0;
+
+ return $self->{data} if $#_ == -1;
return $self->{data}->{ $_[0] } if $#_ == 0;
my %data = @_;
@@ -92,7 +93,11 @@ sub play {
my %override = @_;
return unless defined $play_data;
-
+
+ if ( ref $play_data eq '') {
+ $play_data = $self->{data}->{$play_data};
+ }
+
my $volume = $play_data->{volume} || $override{volume} || 50;
my $fade_in = $play_data->{fade_in} || $override{fade_in} || 0;
my $loops = $play_data->{loops} || $override{loops} || 1;
View
55 lib/SDLx/Surface.pm
@@ -123,9 +123,7 @@ sub get_pixel {
sub set_pixel {
my ( $self, $y, $x, $new_value ) = @_;
-
$new_value = SDLx::Validate::num_rgba($new_value);
-
SDLx::Surface::set_pixel_xs( $self, $x, $y, $new_value );
}
@@ -190,6 +188,8 @@ sub load {
}
}
+
+
my $formated_surface = $surface;
if( SDL::Video::get_video_surface )
{
@@ -201,6 +201,33 @@ sub load {
#EXTENSTIONS
+sub blit {
+ my ( $src, $dest, $src_rect, $dest_rect ) = @_;
+
+ $src = SDLx::Validate::surface($src);
+ $dest = SDLx::Validate::surface($dest);
+
+ if(defined $src_rect) {
+ $src_rect = SDLx::Validate::rect($src_rect);
+ }
+ else {
+ $src_rect = SDL::Rect->new( 0, 0, $src->w, $src->h );
+ }
+ if(defined $dest_rect) {
+ $dest_rect = SDLx::Validate::rect($dest_rect);
+ }
+ else {
+ $dest_rect = SDL::Rect->new( 0, 0, $dest->w, $dest->h );
+ }
+
+ SDL::Video::blit_surface(
+ $src, $src_rect,
+ $dest, $dest_rect
+ );
+
+ return $src;
+}
+
sub blit_by {
my ( $dest, $src, $src_rect, $dest_rect ) = @_;
SDLx::Surface::blit( $src, $dest, $src_rect, $dest_rect );
@@ -218,13 +245,13 @@ sub update {
my ( $surface, $rects ) = @_;
if ( !defined($rects) || ( ref($rects) eq 'ARRAY' && !ref( $rects->[0] ) ) ) {
- my @rect;
- @rect = @{$rects} if $rects;
+ my @rect;
+ @rect = @{$rects} if $rects;
$rect[0] ||= 0;
$rect[1] ||= 0;
$rect[2] ||= $surface->w;
$rect[3] ||= $surface->h;
-
+
SDL::Video::update_rect( $surface, @rect );
} else {
SDL::Video::update_rects( $surface, map { SDLx::Validate::rect($_) } @{$rects} );
@@ -233,6 +260,20 @@ sub update {
return $surface;
}
+sub draw_rect {
+ my ( $self, $rect, $color ) = @_;
+ $color = SDLx::Validate::map_rgba( $color, $self->format );
+ if ( defined $rect ) {
+ $rect = SDLx::Validate::rect($rect);
+ } else {
+ $rect = SDL::Rect->new( 0, 0, $self->w, $self->h );
+ }
+
+ SDL::Video::fill_rect( $self, $rect, $color )
+ and Carp::confess "Error drawing rect: " . SDL::get_error();
+ return $self;
+}
+
sub draw_line {
my ( $self, $start, $end, $color, $antialias ) = @_;
@@ -273,7 +314,7 @@ sub draw_circle {
unless( $antialias )
{
- SDL::GFX::Primitives::circle_color( $self, @{$center}, $radius, $color );
+ SDL::GFX::Primitives::circle_color( $self, @{$center}, $radius, $color );
}
else
{
@@ -283,7 +324,7 @@ sub draw_circle {
}
sub draw_circle_filled {
- my ( $self, $center, $radius, $color) = @_;
+ my ( $self, $center, $radius, $color ) = @_;
unless ( SDL::Config->has('SDL_gfx_primitives') ) {
Carp::cluck("SDL_gfx_primitives support has not been compiled");
View
30 lib/pods/SDL/Deprecated.pod
@@ -11,6 +11,36 @@ Core
=head1 RELEASES
+=head2 2.xxx
+
+SDLx::App had a full rewrite and SDLx::Controller was updated.
+
+=over
+
+=item SDLx::App
+
+Shortcut aliases in the constructor have been changed and removed. The main ones people use are still there like
+C<w>, C<h> and C<d>. These lesser used ones no longer work: C<t>, C<it>, C<i>, C<s>, C<ab>, C<db>, C<bs>, C<st>, C<asyncblit>.
+
+C<warp> was renamed to C<warp_cursor>, but this method wasn't documented before anyway.
+
+All OpenGL parameters for the constructor now have a C<gl_> prefix. These were never documented,
+so they're not listed here.
+
+The OpenGL method C<attribute> is now called C<gl_attribute>.
+
+C<delay> has been removed and replaced with SDLx::Controller's C<sleep>. C<ticks> has been deprecated, but left in
+for backcompat.
+
+=item SDLx::Controller
+
+The C<eoq> parameter and method have been removed. The exit on quit (stop on quit) action is now enabled by default.
+The C<stop_handler> parameter and method are now used to change and disable the quit action of the app.
+
+C<max_t> will now slow the application down if it runs at less than 10 FPS, by default.
+
+=back
+
=head2 2.517
Major changes to C<SDLx::Controller>.
View
123 lib/pods/SDL/Events.pod
@@ -15,7 +15,7 @@ Most likely you just want to know how to get events for you app.
use SDL::Event;
use SDL::Events ':all';
- SDL::init(SDL_INIT_VIDEO); # Event can only be grabbed in the same thread as this
+ SDL::init(SDL_INIT_VIDEO); # Event can only be grabbed in the same thread as this
...
@@ -27,7 +27,7 @@ Most likely you just want to know how to get events for you app.
while( SDL::Events::poll_event($event) )
{
#check by event type
- on_active() if $event->type == SDL_ACTIVEEVENT;
+ on_active() if $event->type == SDL_ACTIVEEVENT;
...
}
}
@@ -198,6 +198,11 @@ Export tag ':keymod'
KMOD_MODE
KMOD_RESERVED
+Export tag ':repeat'
+
+ SDL_DEFAULT_REPEAT_DELAY
+ SDL_DEFAULT_REPEAT_INTERVAL
+
=head1 METHODS
=head2 pump_events
@@ -206,24 +211,24 @@ Pumps the event loop, gathering events from the input devices.
pump_events();
-pump_events gathers all the pending input information from devices and places it on the event queue. Without calls to pump_events no events would
-ever be placed on the queue.
-Often the need for calls to pump_events is hidden from the user since L</poll_event> and L</wait_event> implicitly call pump_events.
+pump_events gathers all the pending input information from devices and places it on the event queue. Without calls to pump_events no events would
+ever be placed on the queue.
+Often the need for calls to pump_events is hidden from the user since L</poll_event> and L</wait_event> implicitly call pump_events.
However, if you are not polling or waiting for events (e.g. you are filtering them), then you must call pump_events to force an event queue update.
-=head2 peep_events (event, num_events, action, mask)
+=head2 peep_events (event, num_events, action, mask)
-Checks the event queue for messages and optionally returns them.
+Checks the event queue for messages and optionally returns them.
my $num_peep_events = SDL::Events::peep_events($event, 127, SDL_PEEKEVENT, SDL_ALLEVENTS);
If action is SDL_ADDEVENT, up to numevents events will be added to the back of the event queue.
-If action is SDL_PEEKEVENT, up to numevents events at the front of the event queue, matching mask, will be returned and will not be removed from
+If action is SDL_PEEKEVENT, up to numevents events at the front of the event queue, matching mask, will be returned and will not be removed from
the queue.
-If action is SDL_GETEVENT, up to numevents events at the front of the event queue, matching mask, will be returned and will be removed from the
+If action is SDL_GETEVENT, up to numevents events at the front of the event queue, matching mask, will be returned and will be removed from the
queue.
The mask parameter is a bitwise OR of SDL::Events::SDL_EVENTMASK(event_type), for all event types you are interested in
@@ -239,14 +244,14 @@ Examples of mask:
=item SDL_EVENTMASK (SDL_KEYUP)
=item (SDL_EVENTMASK (SDL_MOUSEBUTTONDOWN) | SDL_EVENTMASK (SDL_MOUSEBUTTONUP))
-
+
=item SDL_ALLEVENTS
-
+
=item SDL_KEYUPMASK
-
+
=item SDL_ALLEVENTS ^ SDL_QUITMASK
-=back
+=back
=head3 RETURN
@@ -254,26 +259,26 @@ Number of Events actually stored or -1 if there was an error
=head2 poll_event($event)
-Polls for currently pending events.
+Polls for currently pending events.
If $event is not NULL, the next event is removed from the queue and stored in the L<SDL::Event> structure pointed to by $event.
-As this function implicitly calls pump_events, you can only call this function in the thread that set the video mode with
-L<SDL::Video::set_video_mode|SDL::Video/"set_video_mode">.
+As this function implicitly calls pump_events, you can only call this function in the thread that set the video mode with
+L<SDL::Video::set_video_mode|SDL::Video/"set_video_mode">.
=head3 RETURN
-Returns 1 if there are any pending events, or 0 if there are none available.
+Returns 1 if there are any pending events, or 0 if there are none available.
=head2 push_event($event)
-Pushes an event onto the event queue
+Pushes an event onto the event queue
-The event queue can actually be used as a two way communication channel. Not only can events be read from the queue, but the user can also push
-their own events onto it. event is a pointer to the event structure you wish to push onto the queue.
+The event queue can actually be used as a two way communication channel. Not only can events be read from the queue, but the user can also push
+their own events onto it. event is a pointer to the event structure you wish to push onto the queue.
The event is copied into the queue, and the caller may dispose of the memory pointed to after push_event returns.
-Note: Pushing device input events onto the queue doesn't modify the state of the device within SDL.
+Note: Pushing device input events onto the queue doesn't modify the state of the device within SDL.
This function is thread safe, and can be called from other threads safely.
@@ -287,8 +292,8 @@ Waits indefinitely for the next available $event, returning 0 if there was an er
If $event is not NULL, the next event is removed from the queue and stored in $event.
-As this function implicitly calls SDL_PumpEvents, you can only call this function in the thread that
-L<SDL::Video::set_video_mode|SDL::Video/"set_video_mode">.
+As this function implicitly calls SDL_PumpEvents, you can only call this function in the thread that
+L<SDL::Video::set_video_mode|SDL::Video/"set_video_mode">.
=head3 RETURN
@@ -296,7 +301,7 @@ L<SDL::Video::set_video_mode|SDL::Video/"set_video_mode">.
=head2 set_event_filter
-Sets up a filter to process all events
+Sets up a filter to process all events
my $filter = sub { if($_[0]->type == SDL_ACTIVEEVENT){ return 0} else{ return 1; }};
@@ -308,15 +313,15 @@ set_event_filter takes a coderef that it checks all events again. The callback g
sub { my $event_to_test = shift; ...}
-to filter the event return a 0, to pass the filter return a 1.
+to filter the event return a 0, to pass the filter return a 1.
-One B<Caveat> is if you are filtering SDL_QUIT the event will be filtered if it is non-intterupt call ( Window closes normally ). If it is a
-interrupt SDL_QUIT it will be process on the next event poll.
+One B<Caveat> is if you are filtering SDL_QUIT the event will be filtered if it is non-intterupt call ( Window closes normally ). If it is a
+interrupt SDL_QUIT it will be process on the next event poll.
-Events pushed onto to the queue with L<SDL::Events::push_events|SDL::Events/"push_events"> or L<SDL::Events::peep_events|SDL::Events/"peep_events">
+Events pushed onto to the queue with L<SDL::Events::push_events|SDL::Events/"push_events"> or L<SDL::Events::peep_events|SDL::Events/"peep_events">
do not get filtered.
-This callback may run in a different thread.
+This callback may run in a different thread.
=head2 get_key_state
@@ -328,7 +333,7 @@ Get a snapshot of the current keyboard state
Use L<SDL::Events::pump_events|SDL::Events/"pump_events"> to update the state array.
-This function gives you the current state after all events have been processed, so if a key or button has been pressed and released before you
+This function gives you the current state after all events have been processed, so if a key or button has been pressed and released before you
process events, then the pressed state will never show up in the get_key_state call.
This function doesn't take into account whether shift has been pressed or not.
@@ -345,19 +350,19 @@ Return value is an OR'd combination of KMOD_*
my $mod_state = SDL::Events::get_mod_state();
- # Check which ones are pressed with
+ # Check which ones are pressed with
# no mod pressed?
-
+
print 'no_mod' if ( $mod_state & KMOD_NONE );
- # CTRL or ALT
+ # CTRL or ALT
print 'ctrl alt' if ($mod_state & KMOD_CTRL || $mod_state & KMOD_ALT );
=head3 MOD VALUES
-=over
+=over
=item KMOD_NONE
@@ -383,7 +388,7 @@ Return value is an OR'd combination of KMOD_*
=item KMOD_MODE
-=item KMOD_CTRL
+=item KMOD_CTRL
same as KMOD_LCTRL|KMOD_RCTRL
@@ -414,7 +419,7 @@ Simply pass your desired modifier states into $modstate. This value can be a OR'
Any KMOD_* constant see L<SDL::Events::get_mod_state|SDL::Events/"get_mod_state"> for constants.
SDL::Events::set_mod_state( $modstate );
-=head2 event_state
+=head2 event_state
Allows you to set the state of processing certain events
@@ -454,16 +459,16 @@ Gets the name of the a SDL virtual keysym
Returns a string with the name of the key sym.
-=head2 enable_unicode
+=head2 enable_unicode
Enable/Disable UNICODE translation
my $previous_translation_mode = SDL::Events::enable_unicode( 1 ); #enable
$previous_translation_mode = SDL::Events::enable_unicode( 0 ); #disables
-To obtain the character codes corresponding to received keyboard events, Unicode translation must first be turned on using this function. The
-translation incurs a slight overhead for each keyboard event and is therefore disabled by default. For each subsequently recieved key down event,
-the unicode member of the L<SDL::Event::key_sym|SDL::Event/"key_sym"> provided structure will be then contain the corresponding character code, or
+To obtain the character codes corresponding to received keyboard events, Unicode translation must first be turned on using this function. The
+translation incurs a slight overhead for each keyboard event and is therefore disabled by default. For each subsequently recieved key down event,
+the unicode member of the L<SDL::Event::key_sym|SDL::Event/"key_sym"> provided structure will be then contain the corresponding character code, or
otherwise zero.
A value of 1 for enabling, 0 for disabling and -1 for unchanged. -1 is usefull for querying the current translation mode.
@@ -472,53 +477,53 @@ Only key press events will be translated not release events.
Returns the previous translation mode as (1,0).
-=head2 enable_key_repeat
+=head2 enable_key_repeat
Sets keyboard repeat rate
my $success = SDL::Events::enable_key_repeat( $delay, $interval );
-Enables or disables the keyboard repeat rate. $delay specifies how long the key must be pressed before it begins repeating, it then repleats at the
+Enables or disables the keyboard repeat rate. $delay specifies how long the key must be pressed before it begins repeating, it then repleats at the
speed specified by $interval. Both $delay and $interval are expressed in milliseconds.
Setting $delay to 0 disables key repeating completely. Good default values are SDL_DEFAULT_REPEAT_DELAY and SDL_DEFAULT_REPEAT_INTERVAL.
Return 0 on success and -1 on fail.
-=head2 get_mouse_state
+=head2 get_mouse_state
Retrives the current state of the mouse
my ($mask,$x,$y) = @{ SDL::Events::get_mouse_state( ) };
- print 'Button Left pressed' if ($mask & SDL_BUTTON_LMASK);
+ print 'Button Left pressed' if ($mask & SDL_BUTTON_LMASK);
- print 'Button Right pressed' if ($mask & SDL_BUTTON_RMASK);
+ print 'Button Right pressed' if ($mask & SDL_BUTTON_RMASK);
- print 'Button Middle pressed' if ($mask & SDL_BUTTON_MMASK);
+ print 'Button Middle pressed' if ($mask & SDL_BUTTON_MMASK);
print $x.','.$y;
-The current button state is returned as a button $bitmask, which can be tested using the the above constants
+The current button state is returned as a button $bitmask, which can be tested using the the above constants
-=head2 get_relative_mouse_state
+=head2 get_relative_mouse_state
Retrives the current relative state of the mouse
my ($mask,$x,$y) = @{ SDL::Events::get_mouse_state( ) };
- print 'Button Left pressed' if ($mask & SDL_BUTTON_LMASK);
+ print 'Button Left pressed' if ($mask & SDL_BUTTON_LMASK);
- print 'Button Right pressed' if ($mask & SDL_BUTTON_RMASK);
+ print 'Button Right pressed' if ($mask & SDL_BUTTON_RMASK);
- print 'Button Middle pressed' if ($mask & SDL_BUTTON_MMASK);
+ print 'Button Middle pressed' if ($mask & SDL_BUTTON_MMASK);
print $x.','.$y; # this is relative to the last postion of the mouse
-The current button state is returned as a button $bitmask, which can be tested using the the above constants
+The current button state is returned as a button $bitmask, which can be tested using the the above constants
-=head2 get_app_state
+=head2 get_app_state
Gets the state of the application
@@ -526,7 +531,7 @@ Gets the state of the application
The $app_state is a bitwise combination of:
-=over
+=over
=item SDL_APPMOUSEFOCUS
@@ -547,22 +552,22 @@ Application is visible
warn 'Application Visible' if $app_state & SDL_APPACTIVE
-=back
+=back
-=head2 joystick_event_state
+=head2 joystick_event_state
Enable/disable joystick event polling
my $status = SDL::Events::joystick_event_state( $state );
-This function is used to enable or disable joystick event processing. With joystick event processing disabled you will have to update joystick
+This function is used to enable or disable joystick event processing. With joystick event processing disabled you will have to update joystick
states with L<SDL::Joystick::update|SDL::Joystick/"update"> and read the joystick information manually. $state can be:
-=over
+=over
=item SDL_QUERY
-=item SDL_ENABLE
+=item SDL_ENABLE
=item SDL_IGNORE
View
6 lib/pods/SDL/Surface.pod
@@ -83,6 +83,12 @@ SDL::Surface width is defined at construction so this is read-only.
Returns the height of the surface.
SDL::Surface height is defined at construction so this is read-only.
+=head2 flags
+
+ my $flags = $surface->flags;
+
+Returns the flags of the surface (bitwise OR-ed L<SDL::Video constants|SDL::Video/CONSTANTS>).
+
=head2 format
my $format = $surface->format;
View
471 lib/pods/SDLx/App.pod
@@ -3,7 +3,7 @@
=head1 NAME
-SDLx::App - a SDL perl extension
+SDLx::App - The root window of an SDL application
=head1 CATEGORY
@@ -11,169 +11,430 @@ Extension
=head1 SYNOPSIS
- use SDL;
- use SDLx::App;
- use SDL::Event;
- use SDL::Events;
-
- my $app = SDLx::App->new(
- title => 'Application Title',
- width => 640,
- height => 480,
- depth => 32
- );
-
-This is the manual way of doing things
-
- my $event = SDL::Event->new; # create a new event
-
- SDL::Events::pump_events();
-
- while ( SDL::Events::poll_event($event) ) {
- my $type = $event->type(); # get event type
- print $type;
- exit if $type == SDL_QUIT;
- }
-
-An alternative to the manual Event processing is through the L<SDLx::Controller> module. L<SDLx::App> is a Controller so see the CALLBACKS section below.
+ use SDL;
+ use SDLx::App;
+ use SDL::Event;
+ use SDL::Events;
+
+ # this is all the code we need to have a working app!
+ my $app = SDLx::App->new;
+
+ # we can also specify many useful things in the constructor
+ my $app = SDLx::App->new(
+ title => 'My Great Game',
+ width => 1024,
+ height => 600,
+ dt => 0.05,
+ centered => 1,
+ no_frame => 1,
+ async_blit => 1,
+ );
+
+ # our app also comes with an SDLx::Controller
+
+ # add a handler handle events such as keypresses
+ $app->add_event_handler(
+ sub {
+ my ($event) = @_;
+ # handle the event here
+ }
+ );
+
+ # add a handler to move our objects in response to time
+ $app->add_move_handler(
+ sub {
+ # handle moving objects here
+ }
+ );
+
+ # add a handler to show our objects on the screen
+ $app->add_show_handler(
+ sub {
+ # handle drawing objects here
+ }
+ );
+
+ # finally, start the app run loop with the added handlers
+ $app->run();
+
+For a full explanation of the L<run|SDLx::Controller/run> loop and other Controller related methods,
+please see L<SDLx::Controller>.
=head1 DESCRIPTION
-L<SDLx::App> controls the root window of the of your SDL based application.
-It extends the L<SDL::Surface> class, and provides an interface to the window
-manager oriented functions.
+The C<SDLx::App> provides methods for the root window of your SDL application,
+as well as many related convenience methods.
+It is a subclass of both L<SDLx::Surface> and L<SDLx::Controller>,
+providing all the methods they both provide.
=head1 METHODS
=head2 new
-C<SDLx::App::new> initializes the SDL, creates a new screen,
-and initializes some of the window manager properties.
-C<SDLx::App::new> takes a series of named parameters:
+ my $app = SDLx::App->new(
+ width => 640,
+ height => 480,
+ depth => 32,
-=over 4
+ title => "Application Title",
+ icon_title => "App Title",
+ icon => "icon.bmp",
+ icon_color_key => [255, 255, 0],
-=item * title
-the window title. Defaults to the file name. Shorter alias: 't'
+ # two ways to do init. init video is assumed regardless
+ init => SDL_INIT_AUDIO | SDL_INIT_JOYSTICK,
+ init => [ 'audio', 'joystick' ],
-=item * icon_title
-the icon title. Defaults to file name. Shortcut: 'it'
+ # normal libsdl access to flags
+ flags => SDL_SWSURFACE | SDL_ANYFORMAT,
+ # or parameter access to flags
+ sw_surface => 1,
+ hw_surface => 1,
+ async_blit => 1,
+ any_format => 1,
+ hw_palette => 1,
+ double_buf => 1,
+ fullscreen => 1,
+ open_gl => 1,
+ resizable => 1,
+ no_frame => 1,
-=item * icon
-the icon itself. Defaults to none. Shortcut: 'i'
+ # window position
+ centered => 1,
+ position => [ 150, 100 ],
-=item * width
-Window width, in pixels. Defaults to 800. Shortcut: 'w'
+ hide_cursor => 1,
+ grab_input => 1,
-=item * height
-Window height, in pixels. Defaults to 600. Shortcut: 'h'
+ # don't initialize an SDLx::Controller for the app
+ no_controller => 1,
-=item * depth
-Screen depth. Defaults to 16. Shortcut: 'd'.
+ # store your goodies in the app if you like
+ stash => {},
-=item * flags
-Any flags you want to pass to L<SDL::Video> upon initialization. Defaults to SDL_ANYFORMAT. Flags should be I<or'ed> together if you're passing more than one (flags => FOO|BAR). Shortcut: 'f'.
+ # and everything from SDLx::Controller
+ dt => 0.1,
+ min_t => 1 / 60,
+ delay => 0,
+ stop_handler => \&SDLx::Controller::default_stop_handler,
+ event => SDL::Event->new(),
+ event_handlers => [],
+ move_handlers => [],
+ show_handlers => [],
+ time => 0,
+ );
-=item * resizeable
-Set this to a true value to make the window resizeable by the user. Default is off.
+Initializes SDL with L<SDLx::App::init|/init>,
+creates the root window with L<SDL::Video::set_video_mode|SDL::Video/set_video_mode>,
+initializes an L<SDLx::Controller> belonging to the app,
+and performs many other app management tasks all as specified by named parameters.
+Returns an L<SDLx::Surface> of the new app.
-=item * exit_on_quit
-Set this to a true value to make the app exit if a SDL_QUIT event is triggered. Shortcut: 'eoq'.
+The complete set of parameters are shown in the code above and explained in detail below.
+When constructing the app's L<SDLx::Controller> all parameters specified are also given to
+L<< SDLx::Controller->new|SDLx::Controller/new >>, so should be specified here. See
+L<SDLx::Controller>.
+
+=over
+
+=item width
+
+The window width, in pixels. Defaults to 640. Alias: C<w>.
+
+=item height
+
+The window height, in pixels. Defaults to 480. Alias: C<h>.
+
+=item depth
+
+The surface's color depth, in bits per pixel. Should be 8, 16, 24 or 32.
+If not defined, defaults to 32 and specifies the
+L<SDL_ANYFORMAT|SDL::Video/CONSTANTS> flag. Alias: C<d>.
+
+=item title
+
+The window's title, as a string. Defaults to the L</icon_title> if defined, or the file name.
+
+=item icon_title
+
+The application's icon title, as a string. Defaults to the L</title> if defined, or the file name.
+This will only have an effect under certain operating systems.
+
+=item icon
+
+The application's icon. Set with the L</icon> method.
+
+=item icon_color_key
+
+You can optionally use this when specifying the C<icon> parameter to set its color key (transparent pixel).
+
+=item init
+
+The SDL subsystems to initialize, as a product of the L<SDL init constants|SDL/CONSTANTS> or an array ref.
+The video subsystem is initialized no matter what, and does not need to be specified.
+The specified value is passed to L<SDLx::App::init|/init>, so see that for more details.
+Defaults to L<SDL_INIT_EVERYTHING|SDL/CONSTANTS>. Alias: C<initialize>.
+
+=item flags
+
+L<SDL::Video flags|SDL::Video/CONSTANTS> to specify when calling
+L<SDL::Video::set_video_mode|SDL::Video/set_video_mode>.
+Flags should be bitwise I<or'ed> together when passing more than one (C<flags => FOO|BAR>).
+All flags have a corresponding named parameter which can be used instead of specifying them here,
+and are explained below.
+Defaults to no flags, or to L<SDL_ANYFORMAT|SDL::Video/CONSTANTS> if the C<depth> parameter was undefined.
+Alias: C<f>.
+
+=item sw_surface
+
+The L<SDL_SWSURFACE|SDL::Video/CONSTANTS> flag, as a boolean. If true, creates the surface in
+system memory. This is best used when you plan to do per-pixel manipulations,
+or blit surfaces with alpha channels. Aliases: C<software_surface>, C<sw>.
+
+=item hw_surface
+
+The L<SDL_HWSURFACE|SDL::Video/CONSTANTS> flag, as a boolean. If true, creates the surface in
+video memory. This is best used when the surfaces you'll be blitting are also hardware surfaces.
+SDL copies the surfaces from video memory to system memory when you L<lock|SDL::Video/lock_surface> them,
+and back when you L<unlock|SDL::Video/unlock_surface> them, which can cause a major performance hit.
+If the video driver does not support hardware surfaces, a software surface will be returned instead.
+Many platforms can only provide hardware surfaces when using L<SDL_FULLSCREEN|SDL::Video/CONSTANTS>.
+Aliases: C<hardware_surface>, C<hw>.
+
+=item async_blit
+
+The L<SDL_ASYNCBLIT|SDL::Video/CONSTANTS> flag, as a boolean. If true, enables the use of asynchronous updates
+of the display surface. This will usually slow down blitting on single-CPU machines, but can speed up blitting
+on multi-CPU machines. Alias: C<asynchronous_blit>.
+
+=item any_format
+
+The L<SDL_ANYFORMAT|SDL::Video/CONSTANTS> flag, as a boolean. If a video surface of the requested
+bits-per-pixel (bpp) is not available SDL will normally emulate one with a shadow surface.
+Passing a true value prevents this and causes SDL to use the video surface, regardless of its pixel depth.
+This flag is specified automatically when the L</depth> parameter is undefined.
+
+=item hw_palette
+
+The L<SDL_HWPALETTE|SDL::Video/CONSTANTS> flag, as a boolean. If true, gives SDL exclusive palette access.
+Without this flag you may not always get the exact colors you request with
+L<SDL::Video::set_colors|SDL::Video/set_colors> or L<SDL::Video::set_palette|SDL::Video/set_palette>.
+Alias: C<hardware_palette>.
+
+=item double_buf
+
+The L<SDL_DOUBLEBUF|SDL::Video/CONSTANTS> flag, as a boolean. If true, enables hardware double buffering;
+faster, but only valid with a hardware surface. L<flip|SDLx::Surface/flip> should be used to flip the buffers
+and update the screen. All drawing will take place on the surface that is not being displayed.
+If double buffering could not be enabled then L<flip|SDLx::Surface/flip> will just perform an
+L<update_rect|SDLx::Surface/update_rect> on the entire screen. Aliases: C<double_buffer>, C<dbl_buf>.
+
+=item fullscreen
+
+The L<SDL_FULLSCREEN|SDL::Video/CONSTANTS> flag, as a boolean. If true, SDL will attempt to use a fullscreen mode,
+changing the hardware resolution to the resolution of the display surface.
+If, for whatever reason, this change is not possible the next higher resolution will be used
+and the display surface centered on a black background. Aliases: C<full_screen>, C<full>.
+
+=item open_gl
+
+The L<SDL_OPENGL|SDL::Video/CONSTANTS> flag, as a boolean. If true, creates an OpenGL rendering context.
+This uses any C<gl> attributes specified and any others set with L</gl_attribute>. Aliases: C<opengl>, C<gl>.
+
+=item resizable
+
+The L<SDL_RESIZABLE|SDL::Video/CONSTANTS> flag, as a boolean. If true, creates a resizable window.
+When the window is resized by the user a L<SDL_VIDEORESIZE|SDL::Events/CONSTANTS> event
+is generated and L</resize> should be called with the new size.
+
+=item no_frame
+
+The L<SDL_NOFRAME|SDL::Video/CONSTANTS> flag, as a boolean. If true, SDL attempts to create a window
+with no title bar or frame decoration. Fullscreen modes automatically have this flag set.
+
+=item centered
+
+A boolean value. If true, creates the window centered on the screen.
+SDL does this with the C<SDL_VIDEO_CENTERED> environment variable which is set using C<$ENV{SDL_VIDEO_CENTERED}>.
+Alias: C<center>.
+
+=item position
+
+The position of the window on the screen, as an array ref. The array ref should be two elements long,
+specifying C<x> and C<y> values, in pixels, used to position the window on the screen.
+Implemented using C<$ENV{SDL_VIDEO_WINDOW_POS}>. Alias: C<pos>.
+
+=item hide_cursor
+
+A boolean value. If true, hides the cursor on the video surface using L</show_cursor>.
+A surface can then instead be blitted to the display at the location of the cursor.
+Alias: C<no_cursor>.
+
+=item grab_input
+
+A boolean value. If true, SDL attempts to confine the cursor to the window using L</grab_input>.
+Also, nearly all keyboard input will be passed directly to the application,
+and not interpreted by any window manager present.
+
+=item no_controller
+
+A boolean value. If true, does not initialize an L<SDLx::Controller> for the app.
+Care should then be taken to not use any of L<SDLx::Controller>s methods.
+
+=item stash
+
+A place to store any information you need the app to hold. This can then be returned and set with
+L</stash>. If not specified, defaults to an empty hash ref.
=back
-=head1 METHODS
+=head2 init
-=head2 title()
+ SDLx::App->init( SDL::SDL_INIT_TIMER | SDL::SDL_INIT_AUDIO | ... );
+ SDLx::App->init( [ 'timer', 'audio', 'video', 'cd_rom', 'cdrom', 'joystick',
+ 'everything', 'all', 'no_parachute', 'event_thread' ] );
-=head2 title( $new_title )
+This is used internally by L</new> to init SDL with
+L<SDL::init|SDL/init>. If any subsystems are already initialized, it will use
+L<SDL::init_sub_system|SDL/init_sub_system> instead. You should use this whenever you need to
+init anything outside calls to L</new>, as it will always do what you want.
-=head2 title( $window_title, $icon_title )
+If a number is specified, it will initialize SDL in the same way as L<SDL::init|SDL/init> describes.
+If an array ref is specified, each element should be a string corresponding to a flag to specify.
+The strings and their corresponding flags are shown in the table below. See L<SDL::init|SDL/init> for
+descriptions of what each flag does.
-C<SDLx::App::title> takes 0, 1, or 2 arguments. If no parameter is given,
-it returns the current application window title. If one parameter is
-passed, both the window title and icon title will be set to its value.
-If two parameters are passed the window title will be set to the first,
-and the icon title to the second.
+ flag string alias
+ ==================== ============ ======
+ SDL_INIT_TIMER timer
+ SDL_INIT_AUDIO audio
+ SDL_INIT_VIDEO video
+ SDL_INIT_CDROM cd_rom cdrom
+ SDL_INIT_JOYSTICK joystick
+ SDL_INIT_EVERYTHING everything all
+ SDL_INIT_NOPARACHUTE no_parachute
+ SDL_INIT_EVENTTHREAD event_thread
-=head2 delay( $ms )
+=head2 screen_size
-C<SDLx::App::delay> takes 1 argument, and will sleep the application for
-that many ms.
+ my ($screen_w, $screen_h, $screen_d) = SDLx::App->screen_size();
-=head2 ticks
+Returns the width, height and depth of the user's screen using
+L<SDL::Video::get_video_info|SDL::Video/get_video_info>.
+This can be called before or after calling L</new>.
+Initializing the video subsystem will be handled correctly no matter what thanks to
+L<SDLx::App::init|/init>.
-C<SDLx::App::ticks> returns the number of ms since the application began.
+=head2 set_video_mode
-=head2 error
+ my $app = SDLx::App->set_video_mode( $w, $h, $d, $f );
+ $app->set_video_mode( $w, $h, $d, $f );
+
+The first form is used internally by L</new> to create the new SDL display surface.
+The second form can be used to change the video mode of an existing app.
+See L<SDL::Video::set_video_mode|SDL::Video/set_video_mode> for a description on what the
+four arguments do.
-C<SDLx::App::error> returns the last error message set by the SDL.
+=head2 resize
-=head2 resize( $width, $height )
+ $app->resize( $w, $h );
-C<SDLx::App::resize> takes a new width and height of the application. Only
-works if the application was originally created with the resizable option.
+Resizes the app to the specified width and height. The surface's depth and flags will remain the same.
=head2 fullscreen
-C<SDLx::App::fullscreen> toggles the application in and out of fullscreen mode.
+ $app->fullscreen();
+
+Toggles the app in and out of fullscreen mode in a cross-platform-friendly way.
+Returns false if the app fails to go fullscreen for some reason. Otherwise, returns true.
=head2 iconify
-C<SDLx::App::iconify> iconifies the application window.
+ $app->iconify();
-=head2 grab_input( $CONSTANT )
+Attempts to minimize the window with L<SDL::Video::wm_iconify_window|SDL::Video/wm_iconify_window>.
+The exact behavior depends on the operating system.
-C<SDLx::App::grab_input> can be used to change the input focus behavior of
-the application. It takes one argument, which should be one of the following:
+=head2 title
-=over 4
+ my ( $title, $icon_title ) = $app->title();
+ $app->title( $title, $icon_title );
-=item * SDL_GRAB_QUERY
+If no arguments are specified, returns a list of the title and the icon title.
+If arguments are specified, the titles will be set instead. Specify undef to keep the title or
+icon title the same, or a string to modify them.
-=item * SDL_GRAB_ON
+=head2 icon
-=item * SDL_GRAB_OFF
+ SDLx::App->icon( $filename, $color );
+ SDLx::App->icon( $surface, $color );
-=back
+Sets the window's icon.