430 lines
17 KiB
Markdown
430 lines
17 KiB
Markdown
# node-sdl ( Simple DirectMedia Layer bindings for node.js )
|
|
|
|
## 0. Installation
|
|
|
|
Installation of the node-sdl package is straight-forward: first clone the
|
|
package using git, then build the C++ portion of the package with the
|
|
node-waf command.
|
|
|
|
This package depends on the SDL libraries being present on the target system.
|
|
The following command was required to install these libraries on a "stock"
|
|
Ubuntu 11.04 install:
|
|
|
|
<pre> sudo apt-get install libsdl1.2-dev libsdl-image1.2-dev libsdl-ttf2.0-dev</pre>
|
|
|
|
Now that your library dependencies are satisfied, check out the source from
|
|
github:
|
|
|
|
<pre> git clone https://github.com/creationix/node-sdl.git</pre>
|
|
|
|
Second, build the package:
|
|
|
|
<pre> cd node-sdl
|
|
node-waf configure build</pre>
|
|
|
|
You can test if the package was properly built by running one or more of the
|
|
example programs:
|
|
|
|
<pre> cd examples
|
|
node img.js</pre>
|
|
|
|
## 1. Usage
|
|
|
|
### 1.1. Initialization and Shutdown
|
|
|
|
Begin by requiring the node-sdl package and calling the init() function:
|
|
|
|
<pre> var SDL = require( 'sdl' );
|
|
SDL.init( SDL.INIT.VIDEO )</pre>
|
|
|
|
The init() function takes a numeric parameter telling the library what
|
|
subsystems to initialize. The node-sdl package defines the following
|
|
constants:
|
|
|
|
<pre> SDL.INIT.TIMER - initializes timers (not currently supported)
|
|
SDL.INIT.AUDIO - initialize audio subsystem (not currently supported)
|
|
SDL.INIT.VIDEO - initialize video subsystem
|
|
SDL.INIT.CDROM - initialize CD playback subsystem (not currently supported)
|
|
SDL.INIT.JOYSTICK - initialize joystick support
|
|
SDL.INIT.EVERYTHING - all of the above
|
|
SDL.INIT.NOPARACHUTE - don't catch fatal signals
|
|
</pre>
|
|
|
|
Two or more of these parameters may be selected by or-ing them together:
|
|
|
|
<pre> SDL.init( SDL.INIT.VIDEO | SDL.INIT.JOYSTICK );</pre>
|
|
|
|
The QUIT event signals the closure of a SDL managed window, so adding a
|
|
function that exits the application when it is received may be useful:
|
|
|
|
<pre> SDL.events.on( 'QUIT', function( evt ) { process.exit( 0 ); } );</pre>
|
|
|
|
Exiting the application when the user presses Control-C or the Escape key
|
|
can be achieved by adding a listener to the KEYDOWN event:
|
|
|
|
<pre> SDL.events.on( 'KEYDOWN', function ( evt ) {
|
|
if( ( ( evt.sym === 99 ) && ( evt.mod === 64 ) ) ||
|
|
( ( evt.sym === 27 ) && ( evt.mod === 0 ) ) ) {
|
|
process.exit( 0 );
|
|
}
|
|
} );</pre>
|
|
|
|
### 1.2. Video Functions
|
|
|
|
To create a window under SDL control, use the setVideoMode() function to
|
|
create a "surface".
|
|
|
|
<pre> var screen = SDL.setVideoMode( 640, 480, 32, SDL.SURFACE.SWSURFACE );</pre>
|
|
|
|
The setVideoMode() function takes four parameters: surface width, surface
|
|
height, bit depth and surface flags. The flags parameter selects options for
|
|
the video buffer:
|
|
|
|
<pre> SDL.SURFACE.SWSURFACE - video buffer created in system memory
|
|
SDL.SURFACE.HWSURFACE - video buffer created in video memory
|
|
SDL.SURFACE.ASYNCBLIT - enable async updates of display surface
|
|
SDL.SURFACE.ANYFORMAT - don't emulate unavailable BPPs with a shadow surface
|
|
SDL.SURFACE.HWPALETTE - give SDL exclusive palette access (not supported)
|
|
SDL.SURFACE.DOUBLEBUF - enable hardware double buffering. (only works with
|
|
SDL.SURFACE.HWSURFACE)
|
|
SDL.SURFACE.FULLSCREEN - use fullscreen mode
|
|
SDL.SURFACE.OPENGL - create an OpenGL rendering context (not supported)
|
|
SDL.SURFACE.RESIZABLE - create a resizable window
|
|
SDL.SURFACE.HWACCEL - use hardware accelerated blitter
|
|
SDL.SURFACE.SRCCOLORKEY - use color key blitter
|
|
SDL.SURFACE.RLEACCEL - color key blitting is accelerated with RLE
|
|
SDL.SURFACE.SRCALPHA - surface blit uses alpha blending
|
|
SDL.SURFACE.PREALLOC - surface uses preallocated memory
|
|
</pre>
|
|
|
|
Like other numeric constants, they may be combined with the or operator:
|
|
|
|
<pre> var screen = SDL.setVideoMode( 640, 480, 32, SDL.SURFACE.HWSURFACE | SDL.SURFACE.HWACCEL );</pre>
|
|
|
|
The surface created with the setVideoMode() call represents the contents of
|
|
the displayed window. It's common practice to create a buffer surface to hold
|
|
video contents in preparation for drawing on the screen. To create a buffer,
|
|
use the createRGBSurface() call.
|
|
|
|
<pre> var surface = SDL.createRGBSurface( SDL.SURFACE.SWSURFACE, 24, 24 );</pre>
|
|
|
|
The first parameter describes the type of surface to create, and the remaining
|
|
parameters are x and y sizes.
|
|
|
|
After you're done using a surface, you *should* free it. The freeSurface()
|
|
function takes a surface (like one returned from the createRGBSurface()
|
|
function above) and frees memory associated with it:
|
|
|
|
<pre> SDL.freeSurface( surface );</pre>
|
|
|
|
The displayFormat() function copies a surface into a new surface suitable
|
|
for blitting into the frame buffer. It takes a surface as it's first (and only)
|
|
parameter and returns a new surface conformable with the system's frame buffer.
|
|
This call is extremely useful in conjunction with the SDL.IMG.load() call:
|
|
|
|
<pre> var tempSheet = SDL.IMG.load( __dirname + "/sprites.png" );
|
|
var sheet = SDL.displayFormat( tempSheet );
|
|
SDL.freeSurface( tempSheet );</pre>
|
|
|
|
SDL surfaces may have an Alpha value associated with them. This is a value from
|
|
0 to 255 and sets the transparency of the surface's contents when blitted into
|
|
another surface (like the frame buffer).
|
|
|
|
<pre> SDL.setAlpha( sheet, SDL.SURFACE.SRCALPHA | SRC.SURFACE.RLEACCEL, 192 );</pre>
|
|
|
|
Options to the setAlpha() function include:
|
|
|
|
<pre> SDL.SURFACE.SRCALPHA - specifies that alpha blending should be used
|
|
SLD.SURFACE.RLEACCEL - specifies that RLE acceleration should be used for blitting</pre>
|
|
|
|
You can set a specific color to be transparent (i.e. - the color key) using the
|
|
setColorKey() function. After setting this value, when the surface's contents
|
|
are blitted to another surface, pixels with the color key value won't be copied.
|
|
|
|
<pre> SDL.setColorKey( sheet, SDL.SURFACE.SRCCOLORKEY, 0x01010100 );</pre>
|
|
|
|
The first parameter is the surface whose color key you're setting. The second
|
|
is a set of flags that may be or'd together. The third is a 32 bit integer
|
|
representing the value of the color key you want to use. Values for the flags
|
|
include:
|
|
|
|
<pre> SDL.SURFACE.SRCCOLORKEY - means you're setting the surface's color key
|
|
SDL.SURFACE.RLEACCEL - you want to enable RLE accleration
|
|
0 - means you want to clear the surface's color key
|
|
</pre>
|
|
|
|
It can sometimes be tricky to get the precise color key value if you're using
|
|
multiple surface geometries. Fortunately, you can use the mapRGB() function
|
|
to return a color value, modified to account for a surface's color geometry.
|
|
In other words, do this when you want to set the color key:
|
|
|
|
<pre> var colorKey = [ 255, 0, 0 ]; // setting the color key to red
|
|
SDL.setColorKey( sheet,
|
|
SDL.SURFACE.SRCCOLORKEY | SDL.SURFACE.RLEACCEL,
|
|
SDL.mapRGB( sheet.format,
|
|
colorKey[0],
|
|
colorKey[1],
|
|
colorKey[2] ) );</pre>
|
|
|
|
To fill a rectangle with a particular color, use the fillRect() function.
|
|
|
|
<pre> SDL.fillRect( surface, [0, 0, 24, 24], 0xFF8080AF );</pre>
|
|
|
|
To blit (copy) a portion of one surface into anotehr, use the blitSurface()
|
|
function. It takes as it's parameters: the source surface, a rectangle
|
|
describing the origin and extent of the pixels to be copied, the destination
|
|
surface, and a point in the destination you're copying pixels to.
|
|
|
|
So the following example copies an 8x16 rectangle from position (10,25) in the
|
|
spriteSource surface into position (128,15) in the screen surface:
|
|
|
|
<pre> SDL.blitSurface( spriteSource, [10, 25, 8, 16], screen, [128, 15] );</pre>
|
|
|
|
After making changes to a surface, you use the flip() function to instruct
|
|
the system to make the changes apparent. In systems that support hardware
|
|
double-buffering, this call "does the right thing" and waits for a vertical
|
|
retrace to flip between video screens. On systems with a software surface, it
|
|
simply makes sure that the contents of the surface are made visible.
|
|
|
|
It's very useful to call this command after you make updates to the screen. For
|
|
example:
|
|
|
|
<pre> var screen = SDL.setVideoMode( 640, 480, 32, SDL.SURFACE.SWSURFACE );
|
|
SDL.fillRect( surface, [0, 0, 24, 24], 0xFF8080AF );
|
|
SDL.flip( screen );
|
|
</pre>
|
|
|
|
### 1.3. Image Related Functions
|
|
|
|
This package uses a supplimentary image library intended to make it easy for
|
|
node-sdl applications to load and use JPG, PNG or TIFF images. Before using
|
|
Image functions, you should initalize them with the image init() function:
|
|
|
|
<pre> SDL.IMG.init( 0 );</pre>
|
|
|
|
To load an image into memory, use the image load() function. It takes a file
|
|
path as a parameter and returns a reference to it. The following line loads
|
|
a PNG file called "foo.png" into the variable foo.
|
|
|
|
<pre> var foo = SDL.IMG.load( __dirname + '/foo.png' );</pre>
|
|
|
|
The foo variable can now be used as a surface blit calls (see below.)
|
|
|
|
After you are finished using the image functions, be sure to use the image
|
|
quit() function:
|
|
|
|
<pre> SDL.IMG.quit();</pre>
|
|
|
|
### 1.4. Joystick Functions
|
|
|
|
If you are developing an application that uses joysticks, you'll need to pass
|
|
the SDL.INIT.JOYSTICK option along to the SDL.init() call:
|
|
|
|
<pre> SDL.init( SDL.INIT.VIDEO | SDL.INIT.JOYSTICK );</pre>
|
|
|
|
Now that your app knows you want to use joysticks, you can detect the number of
|
|
joysticks present with the numJoysticks() function. The following code checks
|
|
to see if there's at least one joystick and complains if there's not:
|
|
|
|
<pre> var numPlayers = SDL.numJoysticks();
|
|
if( numPlayers < 1 ) {
|
|
console.log( 'Blargh! At least one joystick is required!' );
|
|
process.exit( 2 );
|
|
}</pre>
|
|
|
|
On systems with multiple joysticks, it might be useful to offer a player a
|
|
selection of which joystick to use. The system assigns a human readable name
|
|
for a joystick which the app can query with the joystickName() function. The
|
|
following code prints out the name of each joystick:
|
|
|
|
<pre> SDL.init( SDL.INIT.VIDEO | SDL.INIT.JOYSTICK );
|
|
var stickCount = SDL.numJoysticks();
|
|
|
|
for( var i = 0; i < stickCount; i ++ ) {
|
|
console.log( 'joystick ' + i + ': ' + SDL.joystickName( i ) );
|
|
}
|
|
|
|
// etc</pre>
|
|
|
|
Now you must explicitly open each joystick you want to receive inputs from. Do
|
|
this with the joystickOpen() function. This function takes an integer as a
|
|
parameter and represents the index of the joystick you want to open. Here is
|
|
some code that opens joystick number zero:
|
|
|
|
<pre> SDL.joystickOpen( 0 );</pre>
|
|
|
|
After the joystick is opened, it will start to generate events. You can register
|
|
event handlers with the SDL.events.on() function. Joystick related events are
|
|
described in the events section below.
|
|
|
|
### 1.5. Window Manager Functions
|
|
|
|
node-sdl is capable of setting window manager related info with the SDL.WM.*
|
|
functions.
|
|
|
|
To set the title of a SDL window, use the setCaption() function. This fragment
|
|
sets the window's title to "Window Title" and (if supported by your window
|
|
manager) sets the name of the minimized icon to "Icon Title"
|
|
|
|
<pre> SDL.WM.setCaption( 'Window Title', 'Icon Title' );</pre>
|
|
|
|
To set the application's icon, use the setIcon() function. It expects an image
|
|
to be passed as it's parameter, so it's common practice to use the image load()
|
|
function. The following example loads an icon from the file 'eight.png' and
|
|
uses it as the app's icon:
|
|
|
|
<pre> SDL.WM.setIcon( SDL.IMG.load( __dirname + '/eight.png' ) );</pre>
|
|
|
|
## 2. Events
|
|
|
|
node-sdl uses javascript events to communicate certain conditions. The
|
|
events.on() function is used to set handlers for these events. Event handlers
|
|
are passed an object describing the event as a parameter.
|
|
|
|
### 2.1. Quit
|
|
|
|
As described above, the QUIT event is called when the user closes a SDL window.
|
|
The proper response is to free buffers, and exit:
|
|
|
|
<pre> SDL.events.on( 'QUIT', function ( evt ) {
|
|
SDL.IMG.quit();
|
|
process.exit( 0 );
|
|
} );</pre>
|
|
|
|
### 2.2. KEYDOWN & KEYUP
|
|
|
|
The KEYDOWN and KEYUP events signal the app that the user has pressed (or
|
|
released) a key. The event passed to the handler includes the following
|
|
properties:
|
|
|
|
<pre> scancode - the scancode of the key pressed
|
|
sym - the symbol of the key pressed
|
|
mod - key modifier</pre>
|
|
|
|
Key scancodes are hardware and locale dependent; it's recommended they be
|
|
left alone unless you really are targeting a specific piece of hardware. Key
|
|
symbols are numbers representing keyboard glyphs. Key modifiers represent
|
|
shift, meta, alt and control keys. As you might expect, it's possible for
|
|
multiple modifiers to be pressed simultaneously, so the mod value is a bit
|
|
field with the following definitions:
|
|
|
|
<pre>
|
|
0x0000 - No modifiers pressed
|
|
0x0001 - Left Shift
|
|
0x0002 - Right Shift
|
|
0x0040 - Left Control Key
|
|
0x0080 - Right Control Key
|
|
0x0100 - Left Alt Key
|
|
0x0200 - Right Alt Key
|
|
0x0400 - Left Meta Key (for hardware that has a meta key)
|
|
0x0800 - Right Meta Key (for hardware that has a meta key)
|
|
0x1000 - Num Lock on
|
|
0x2000 - Caps Lock on
|
|
0x4000 - Mode Key Pressed (bonus points if you can find hardware with a mode key)
|
|
</pre>
|
|
|
|
It should probably be noted that SDL keysyms are not exactly ASCII. Most
|
|
importantly, the system will not return a capital letter ASCII code when the
|
|
user hits a letter key and the shift key. Instead, you must manually check
|
|
for the shift key being pressed, check the modifier bits and adjust the key
|
|
code accordingly.
|
|
|
|
The following code converts the modifier and symbol to an ascii value:
|
|
|
|
<pre> SDL.events.on( 'KEYDOWN', function( evt ) {
|
|
var ascii = evt.sym;
|
|
|
|
if( ( ascii < 123 ) && ( ascii > 96 ) ) {
|
|
if( 0 != ( evt.mod && 0x2003 ) ) {
|
|
ascii -= 32;
|
|
}
|
|
}
|
|
|
|
console.log( 'ascii: ' + ascii );
|
|
} );</pre>
|
|
|
|
### 2.3. MOUSEMOTION
|
|
|
|
When the user moves a mouse over an SDL screen, the system will generate
|
|
MOUSEMOTION events. If you create a handler for these events, every time the
|
|
mouse moves, you'll receive an event with the following properties:
|
|
|
|
<pre> state - button state (as described above)
|
|
x - x position of the mouse pointer
|
|
y - y position of the mouse pointer
|
|
xrel - relative motion of the mouse pointer along the x axis
|
|
yrel - relative motion of the mouse pointer along the y axis</pre>
|
|
|
|
The button state is a bit field with the following values:
|
|
|
|
<pre> 0x0000 - no mouse button pressed
|
|
0x0001 - left mouse button pressed
|
|
0x0002 - middle mouse button pressed
|
|
0x0004 - right mouse button pressed</pre>
|
|
|
|
Take mouse chords with a grain of salt, some systems may be configured to
|
|
emulate a 3 button mouse. In these systems, pressing the left and right button
|
|
together will generate a middle button press (code 0x0002) instead of the
|
|
mouse chord you might be expecting (code 0x0005).
|
|
|
|
### 2.4. MOUSEBUTTONDOWN & MOUSEBUTTONUP
|
|
|
|
The MOUSEBUTTONUP and MOUSEBUTTONDOWN events report more data and have
|
|
slightly different semantics than the button state in the MOUSEMOTION event.
|
|
Handlers for these events are passed an object with the following properties:
|
|
|
|
<pre> button - mouse button clicked
|
|
x - x position of the mouse
|
|
y - y position of the mouse</pre>
|
|
|
|
The button property IS NOT a bit field, but an integer. Instead of detecting
|
|
mouse chords, it reports multiple button clicks. Here is the list of mouse
|
|
buttons supported:
|
|
|
|
<pre> 1 - left button
|
|
2 - middle button
|
|
3 - right button
|
|
4 - scroll wheel up
|
|
5 - scroll wheel down</pre>
|
|
|
|
### 2.5. JOYAXISMOTION (Joystick Axis Motion)
|
|
|
|
The JOYAXISMOTION event reports movement of the joystick device along one of
|
|
its axes. Handlers for this event are passed an object with the following
|
|
properties:
|
|
|
|
<pre> which - which joystick generated the event
|
|
axis - which axis (x or y) the event is reporting movement upon
|
|
value - a value from -32768 to 32767 describing the logical position of the joystick</pre>
|
|
|
|
### 2.6. JOYBALLMOTION (Joystick Trackball Motion)
|
|
|
|
If a user's joystick is equipped with a trackball, it may generate these events
|
|
when motion along the trackball is detected. Handlers assigned to listen for
|
|
these events will receive an object with the following properties:
|
|
|
|
<pre> which - which joystick generated the event
|
|
ball - which trackball generated the event
|
|
xrel - relative trackball motion along the x axis
|
|
yrel - relative trackball motion along the y axis</pre>
|
|
|
|
### 2.7. JOYHATMOTION (Joystick Hat Motion)
|
|
|
|
If a user's joystick is equipped with a hat, it may generate these events when
|
|
hat motion is detected. Handlers for this event will be passed an object with
|
|
the following properties:
|
|
|
|
<pre> which - which joystick generated the event
|
|
hat - which hat on the joystick generated the event
|
|
value - the position of the hat</pre>
|
|
|
|
### 2.8. JOYBUTTONDOWN & JOYBUTTONUP
|
|
|
|
If a user's joystick is equipped with buttons, it may generate these events when
|
|
a button press is detected. Handlers for these events will be passed an object
|
|
with the following properties:
|
|
|
|
<pre> which - which joystick generated the event
|
|
button - which button was pressed</pre>
|
|
|