As of SuperGNES version 1.2.21 support for theme-able controllers skins has been implemented. Coming soon is the feature to add user created controller skins. So you can make any theme you can think of! I wanted to make this blog post available first so users can prepare for creating their own controller skins. So lets take a look at one of the SuperGNES controller skins.

This is the default transparent controller skin that comes with SuperGNES. Controllers skins are simply PNG images with extra information embedded in them describing different regions of the controls. You can see from the image elements like the D-Pad and Button Pad. There are action elements that depict the buttons pressed down. Embedding the information in the image makes it easy to share and distribute.

Now lets take a look at the meta information embedded in the image. Inside is the comment text (or PNG tEXtComment ) which contains a structured JSON string. This string holds the controllers name, background color and a list of graphics regions called elements. Each element defines it's own region, id and button type. Formatted below is the actual JSON string for reference.

Here is a hexadecimal dump of the image header. 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 |.PNG........IHDR| 00 00 02 39 00 00 00 ae 08 06 00 00 00 d4 17 1c |...9............| bf 00 00 00 01 73 52 47 42 00 ae ce 1c e9 00 00 |.....sRGB.......| 04 6d 74 45 58 74 43 6f 6d 6d 65 6e 74 00 7b 22 |.mtEXtComment.{"| 6e 61 6d 65 22 3a 22 54 72 61 6e 73 70 61 72 65 |name":"Transpare| ... ...

{ // Controller name displayed "name": "Transparent Default", // Background Color see http://developer.android.com/reference/android/graphics/Color.html "backgroundColor": "#00000000", // Element regions "elements": [ // First element object { // Unique Element id "id": "dpad", // Element Type (supported values: dpad, buttonpad, ltrig, rtrig, start, select, menu, abutton, bbutton, xbutton, ybutton) "type": "dpad", // Rectangular region of graphic "staticBounds": { "bottom": 141, "left": 0, "right": 141, "top": 0 }, // Rectangular region of graphic when pressed "activeBounds": { "bottom": 141, "left": 143, "right": 284, "top": 0 } }, // More elements ... { "activeBounds": { "bottom": 141, "left": 428, "right": 569, "top": 0 }, "type": "buttonpad", "id": "buttonpad", "staticBounds": { "bottom": 141, "left": 286, "right": 427, "top": 0 } }, { "activeBounds": { "bottom": 173, "left": 47, "right": 93, "top": 142 }, "type": "ltrig", "id": "ltrig", "staticBounds": { "bottom": 173, "left": 0, "right": 46, "top": 142 } }, { "activeBounds": { "bottom": 173, "left": 141, "right": 187, "top": 142 }, "type": "rtrig", "id": "rtrig", "staticBounds": { "bottom": 173, "left": 94, "right": 140, "top": 142 } }, { "activeBounds": { "bottom": 173, "left": 188, "right": 250, "top": 142 }, "type": "menu", "id": "menu", "staticBounds": { "bottom": 173, "left": 188, "right": 250, "top": 142 } }, { "activeBounds": { "bottom": 173, "left": 251, "right": 324, "top": 142 }, "type": "start", "id": "start", "staticBounds": { "bottom": 173, "left": 251, "right": 324, "top": 142 } }, { "activeBounds": { "bottom": 173, "left": 325, "right": 404, "top": 142 }, "type": "select", "id": "select", "staticBounds": { "bottom": 173, "left": 325, "right": 404, "top": 142 } } ] }

You can simply download the image above and replace it with your own graphics if you stay within the same regions and use an image editor that preserve image comments. Beyond that you need to understand how the JSON format and element regions work. Each element has a staticBounds property. This consist of four other properties left, right, top and bottom that define the boundary of the control element. To visualize how these relate take a look at the box model below. In addition there is the activeBounds property defining the image pressed or activated state. This allows for an animated interaction. The activeBounds and staticBounds bounds must have the same width and height to be considered valid. If you don't want to create the active graphics simply set the activeBounds to the same coordinates as the staticBounds. Each element must be set a type such as dpad, buttonpad, ltrig, rtrig, start, select, menu, abutton, bbutton, xbutton or ybutton. The dpad and buttonpad types are unique as they require the bounds to be perfectly square for calculating touch regions. It's recommended to use the buttonpad instead of using each abutton, bbutton, xbutton or ybutton. Finally give each element it's own unique identifier. Included below is the Java classes matching with the JSON string for use inside SuperGNES. This is mainly provided for easy reference.

package com.bubblezapgames.supergnes.touchcontrol; import android.graphics.Rect; public class ControllerGraphic { // Controller name displayed public String name; // Background Color see http://developer.android.com/reference/android/graphics/Color.html public String backgroundColor; // Element regions public ControllerGraphicElement elements[]; } public class ControllerGraphicElement { // Unique Element id public String id; // Element Type (supported values: dpad, buttonpad, ltrig, rtrig, start, select, menu, abutton, bbutton, xbutton, ybutton) public String type; // Rectangular region of graphic public Rect staticBounds; // Rectangular region of graphic when pressed public Rect activeBounds; } // No copyright reserved. Public Domain

So now you have an idea of the format of a SuperGNES controller use a photo editing program to create the graphics for your controls. For help inserting comments into images, Gimp has a handy option for doing so. Go to Menu, Image, Image Properties and click on the Comment tab. Also make sure you save your controllers in PNG format and check the "Save comment" option.

Thanks for checking out this blog entry. Look for future releases of SuperGNES with full support and a new controller gallery area here on supergnes.com. Update: With SuperGNES release 1.4.2 user provided controller skins are now fully supported. Simply create the directory "supergnes/controllers" in the root of your device's external storage and copy your PNG controller image into that directory. Your custom controller skin should appear in the controller layout editor. Check the logcat messages on your device for debugging help.