Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: 48fdb0e6c5
Fetching contributors…

Cannot retrieve contributors at this time

357 lines (231 sloc) 9.18 kB

PDL

The Perl Data Language (PDL) is a tool aimed at a more scientific crowd. Accuracy is paramount and speed is the name of the game. PDL brings to Perl fast matrix and numerical calculations. For games in most cases a accuracy is not critical, but speed and efficiency is a great concern. For this reason we will briefly explore how to share SDL texture data between PDL and OpenGL.

This example will do the following:

Make the application

Let's start an application to use with PDL. Make sure you do use PDL.

    + use strict;
    + use warnings;
    + use SDL;
    + use SDL::Video;
    + use SDLx::App;
    +
    + use PDL;
    +
    + my $app = SDLx::App->new(
    +                           title => 'PDL and SDL application',
    +                           width => 640, height => 480, depth => 32,
    +                           eoq => 1);

Attaching the Piddle

PDL core object is something called a piddle. To be able to perform PDL calculations and show them on SDL surfaces, we need to share the memory between them. SDL Surface memory is stored in a void * block called pixels. void * memory has the property that allows Surfaces to have varying depth, and pixel formats. This also means that we can have PDL's memory as our pixels for our surface.

    + sub make_surface_piddle {
    + my ( $bytes_per_pixel, $width, $height) = @_;
    + my $piddle = zeros( byte, $bytes_per_pixel, $width, $height );
    + my $pointer = $piddle->get_dataref();

At this point we have a pointer to the $piddle's memory with the given specifications. Next we have our surface use that memory.

    + my $s = SDL::Surface->new_form( 
    +                                       $pointer, $width, $height, 32, 
    +                                       $width * $bytes_per_pixel 
    +                                      );
    +
    + #Wrap it into a SDLx::Surface for ease of use
    + my $surface = SDLx::Surface->new( surface => $s );
    +
    + return ( $piddle, $surface );
    + } 

Lets make some global variables to hold our $piddle and $surface.

    + my ( $piddle, $surface ) = make_surface_piddle( 4, 400, 200 ); 

Drawing and Updating

make_surface_piddle() will return to use an anonymous array with a $piddle and $surface which we can use with PDL and SDL. PDL will be used to operate on the $piddle. SDL will be used to update the $surface and render it to the SDLx::App.

    + $app->add_move_handler( sub {
    +
    +   SDL::Video::lock_surface($surface);
    + 
    +   $piddle->mslice( 'X',
    +   [ rand(400), rand(400), 1 ],
    +   [ rand(200), rand(200), 1 ] 
    +   ) .= pdl( rand(225), rand(225), rand(225), 255 );
    +
    +   SDL::Video::unlock_surface($surface);
    + } );

SDL::Video::lock_surface prevents SDL from doing any operations on the $surface until SDL::Video::unlock_surface is called. Next we will blit this surface onto the $app.

In this case we use PDL to draw random rectangles of random color.

Running the App

Finally we blit the $surface and update the $app.

    + $app->add_show_handler( sub {
    +
    +    $surface->blit( $app, [0,0,$surface->w,$surface->h], [10,10,0,0] );
    +    $app->update();
    +
    + });

    + $app->run();

Complete Program

OpenGL and SDL

OpenGL is a cross platform library for interactive 2D and 3D graphics applications. However OpenGL specifies only the graphics pipeline and doesn't handle inputs and events. SDL can hand over the graphics component of an application over to OpenGL and take control over the event handling, sound, and textures. In the first example we will see how to set up Perl's OpenGL module with SDLx::App.

SDL Setup

        use strict;
        use warnings;
        use SDL;
        use SDLx::App;

        use OpenGL qw/:all/;

        my $app = SDLx::App->new( 
                title  => "OpenGL App",
                width  => 600,
                height => 600,
                gl     => 1,
                eoq    => 1
           );


        $app->run();

Enabling OpenGL mode is as simple as adding the gl flag to the SDLx::App constructor.

OpenGL Setup

Next we will make a OpenGL perspective with the $app's dimensions:

        glEnable(GL_DEPTH_TEST);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity;
        gluPerspective(60, $app->w/$app->h, 1, 1000 );
        glTranslatef( 0,0,-20);

Additionally we will be initializing glut, but just to draw something quick.

        #Using glut to draw something interesting really quick
        glutInit();

The Render Callback

Now we are prepared to put something on the screen.

        $app->add_show_handler( 
                sub{
                        my $dt = shift;
                
                        #clear the screen
                        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
                        glColor3d(0,1,1);

                        glutSolidTeapot(2); 

                        #sync the SDL application with the OpenGL buffer data
                        $app->sync;


                }
        );

At this point there should be a light blue teapot on the screen. The only special thing to notice here is that we need to call the sync() method on $app. This will flush the buffers and update the SDL application for us.

Event handling

Event handling is the same as any other SDLx::App. We will use the mouse motion changes to rotate the teapot.

First add a global variable to hold your rotate values. And then use those values to rotate our teapot.

      glutInit();

    + my $rotate = [0,0];
     
      $app->add_show_handler( 
        sub{
        my $dt = shift;
    
        #clear the screen
        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glColor3d(0,1,1);

    +   glPushMatrix();

        +       glRotatef($rotate->[0], 1,0,0);
    +   glRotatef($rotate->[1], 0,1,0);

        glutSolidTeapot(2); 

        #sync the SDL application with the OpenGL buffer data
        $app->sync;

   +    glPopMatrix();
        }
    );

Next we will add an event handler to the app to update the rotate values for us.

    $app->add_event_handler(

        sub {
            my ($e ) = shift;

            if( $e->type == SDL_MOUSEMOTION )
                {
                    $rotate =   [$e->motion_x,  $e->motion_y];
                }

        }

    );

Finally we run the application.

    $app->run();

Complete Code

POD ERRORS

Hey! The above document had some coding errors, which are explained below:

Around line 1:

Unknown directive: =head0

Jump to Line
Something went wrong with that request. Please try again.