Tutorials:SDL

Preface
This manual assumes you are already familiar with SDL 1.2. If you want to learn about writing SDL applications, the following links might be useful:
 * Lazy Foo's SDL 1.2 tutorial
 * SDL 1.2 documentation

The code presented in this tutorial uses C/C++ syntax, however the SDL bindings in other languages (ie. Python's PyGame) should be similar, making the content of this page useful also for non-C/C++ applications.

When porting a new application to the GCW Zero, please also read the Software Porting Guidelines.

Initialize video backend
In order to enable video output in SDL, initialize the video backend:

SDL_Init(other_flags|SDL_INIT_VIDEO);

Set up video mode
To set up the video surface, use: SDL_SetVideoMode(width, height, bpp, flags);

SDL will attempt to display any resolution smaller than or equal to 320x240, however the ones known to work are:
 * 320x200 (Displayed as centered, with black bars on top and bottom)
 * 320x240

Valid bpp modes are: 8, 16 or 32. Note that 16 and 32 bits per pixel modes are supported natively, while 8 bpp is converted on-the-fly to 32 bpp.

For hardware accelerated surfaces and double buffering (providing v-sync), use these flags: SDL_HWSURFACE|SDL_DOUBLEBUF In this mode, the framerate will be limited at 60 fps. In case the application is unable to render 60 frames in one second, the framerate will be limited to 30 fps. Please note that in case of lacking support for hardware surfaces, SDL defaults to software surfaces. Take that in mind when testing your GCW Zero software on the PC (Win32 and X11 video backends don't support hardware surfaces). Always test on real GCW Zero hardware to confirm the final effect.

For non v-synced video output, use these flags: SDL_SWSURFACE Please note that software surfaces are slower than hardware surfaces and that with the lack of double buffering, the application will be prone to vertical tearing. Using of this flag is discouraged.

The SDL_FULLSCREEN video flag plays no role on GCW Zero and can be ignored. An example initialization of the video output would be: screen = SDL_SetVideoMode(320, 240, 16, SDL_HWSURFACE|SDL_DOUBLEBUF); for hardware accelerated, double buffered (v-synced), 16 bits per pixel, 320x240 video mode.

Disable mouse cursor
To disable the mouse cursor visibility, call this line right after SDL_SetVideoMode: SDL_ShowCursor(SDL_DISABLE);

Buttons
The GCW Zero buttons are seen by SDL as keyboard events:

In the future it is planned to merge the button interface with analog joystick interface as a single Joystick device. When this happens, the current keyboard interface will remain as optional mode for backwards compatibility.

Joystick
The GCW Zero analog joystick is seen as a Joystick device:

In order to use the analog joystick, you need to initialize SDL with joystick support: SDL_Init(other_flags|SDL_INIT_JOYSTICK);

Then tell SDL which joystick to open: if(SDL_NumJoysticks > 0) SDL_JoystickOpen(0);

It is also a good idea to define a deadzone, so the joystick won't be over-responsive: The value given here is arbitrary - we encourage you to experiment and see what deadzone vs responsiveness ratio fits your program best.
 * 1) define JOY_DEADZONE 500

Implementation
Example implementation of GCW Zero input in SDL:

while(SDL_PollEvent(&event)) { 	switch(event.type) { 		case SDL_QUIT: break; case SDL_KEYDOWN:			// Button press switch(event.key.keysym.sym) { 				case SDLK_LEFT:		// D-PAD LEFT break; case SDLK_RIGHT:	// D-PAD RIGHT break; case SDLK_UP:		// D-PAD UP 				break; case SDLK_DOWN:		// D-PAD DOWN break; case SDLK_LCTRL:	// A 				break; case SDLK_LALT:		// B 				break; case SDLK_LSHIFT:	// X 				break; case SDLK_SPACE:	// Y 				break; case SDLK_TAB:		// Left shoulder break; case SDLK_BACKSPACE:	// Right shoulder break; case SDLK_RETURN:	// Start break; case SDLK_ESCAPE:	// Select break; case SDLK_PAUSE:	// Lock break; default: break; } 		break; case SDL_KEYUP:				// Button release switch(event.key.keysym.sym) { 				case SDLK_LEFT:		// D-PAD LEFT break; case SDLK_RIGHT:	// D-PAD RIGHT break; case SDLK_UP:		// D-PAD UP 				break; case SDLK_DOWN:		// D-PAD DOWN break; case SDLK_LCTRL:	// A 				break; case SDLK_LALT:		// B 				break; case SDLK_LSHIFT:	// X 				break; case SDLK_SPACE:	// Y 				break; case SDLK_TAB:		// Left shoulder break; case SDLK_BACKSPACE:	// Right shoulder break; case SDLK_RETURN:	// Start break; case SDLK_ESCAPE:	// Select break; case SDLK_PAUSE:	// Lock break; default: break; } 		break; case SDL_JOYAXISMOTION:			// Analog joystick movement switch(event.jaxis.axis) { 				case 0:		// axis 0 (left-right) if(event.jaxis.value < -JOY_DEADZONE) { 						// left movement } 					else if(event.jaxis.value > JOY_DEADZONE) { 						// right movement } 				break; case 1:		// axis 1 (up-down) if(event.jaxis.value < -JOY_DEADZONE) { 						// up movement } 					else if(event.jaxis.value > JOY_DEADZONE) { 						// down movement } 				break; default: break; } 		break; default: break; } }

Analog joystick can be also implemented in an alternative way:

Open the joystick device: if(SDL_NumJoysticks > 0) SDL_Joystick* joy = SDL_JoystickOpen(0);

Read values: int joyX = SDL_JoystickGetAxis(joy, 0);	// left-right int joyY = SDL_JoystickGetAxis(joy, 1);	// up-down

Close the device after the joystick input is no longer needed: if(joy) SDL_JoystickClose(joy); If you don't need the full spectrum of the analog accuracy, but instead want to imitate the behaviour of digital D-PAD, introduce two new variables: static int canMoveX = 1; static int canMoveY = 1;

And modify the joystick input code: case 0: if(event.jaxis.value < -JOY_DEADZONE && canMoveX) { 		canMoveX = 0; // left movement } 	else if(event.jaxis.value > JOY_DEADZONE && canMoveX) { 		canMoveX = 0; // right movement } 	else if(event.jaxis.value > -JOY_DEADZONE && event.jaxis.value < JOY_DEADZONE) { 		// is at center canMoveX = 1; } break; case 1: if(event.jaxis.value < -JOY_DEADZONE && canMoveY) { 		canMoveY = 0; // up movement } 	else if(event.jaxis.value > JOY_DEADZONE && canMoveY) { 		canMoveY = 0; // down movement } 	else if(event.jaxis.value > -JOY_DEADZONE && event.jaxis.value < JOY_DEADZONE) { 		// is at center canMoveY = 1; } break; Each axis will now register the input only once, until the joystick is moved back inside the deadzone area.