Introducing the BrightScript 2D API

In many of our recent articles, we have looked at how to use the screen and other UI templates offered by the BrightScript SDK. These components are great for getting your channels developed quickly and for giving them the standard Roku look and feel. There may be times, however, when you want to build something that doesn’t fit into this template model. You might want to implement your own custom grid for displaying poster art, display text in a non-standard way, or create a simple casual game. For many of these situations, the BrightScript 2D Graphics API may be just the thing you are looking for. The 2D API provides a number of fundamental drawing functions for drawing basic shapes, rendering and rotating images, and the like.

In this article we will look at the most basic operations provided by the 2D API. In a later installment we will dive into more advanced topics such as double buffering. Like always, a sample BrightScript channel with full source code accompanies this article. In this case, I’ve written a basic tic tac toe game. The game engine was ported from a free JavaScript sample that can be found at JavaScriptKit. This version of tic tac toe pits you against your Roku Streaming Player. Download the sample from this link and install it onto your player. You can use the remote control arrow keys to move around the playing grid, highlighting the currently focused square as you go. To select your move, press the OK key and a large ‘X’ will be drawn in your selected square. The Roku device will then make its move, drawing a circle in the square it selects. Play continues until one of you wins, or you tie. Please note that this sample game has been written for HD only, and won’t look too great on SD TVs.  A sample of the game screen in shown below.

roScreen and the ifDraw2D Interface

The first thing to know about using the 2D API is that all rendering with the API is done via functions defined on the ifDraw2D interface. This interface is in turn implemented by the roScreen component. Therefore, in order to use the 2D API, your channel needs to create an instance of roScreen. Creating an roScreen instance is as simple as creating any other screen type in BrightScript:

screen = CreateObject(“roScreen”)

When creating an roScreen instance, CreateObject can accept a second optional boolean parameter that indicates whether the screen is double buffered.

screen = CreateObject(“roScreen”, true) ‘This creates a double buffered screen

The 2D API supports alpha blending. To turn on alpha blending call SetAlphaEnable(true). To disable alpha blending call SetAlphaEnable(false). API calls that take a color value include an alpha value that is used when alpha blending is enabled.

Like other BrightScript screen types, roScreen should be assigned a message port so that it can listen for application events such as remote control events.  Once the screen is created, you can start calling 2D API functions.  We will get to some of these shortly.  First though we need to talk about a very key step in drawing 2D graphics.  To guarantee that graphic operations are performed in single buffered screens, your channel needs to call the ifDraw2D method Finish().  Finish is a synchronous API that forces all queued graphics calls to complete.  Before calling Finish, graphics that your channel renders may not be visible to the user.  Keep this in mind as you are experimenting with the 2D API.  If things that you are expecting are not drawing on the screen, check to see if Finish is being called.  Taking the Finish function into account, the typical single buffered 2D API channel will have code that looks like this:

screen = CreateObject("roScreen")
port = CreateObject("roMessagePort")
screen.SetMessagePort(port)
‘Perform various drawing, graphics, etc. operations
screen.Finish()

The majority of the work of course is done by the specific 2D API methods which we introduce next.

Drawing Lines and Rectangles

Perhaps the simplest graphics operations that you can perform with the 2D API are drawing lines and rectangles.  The corresponding API functions are

Boolean DrawLine(Integer xStart, Integer yStart, Integer xEnd, Integer yEnd, Integer rgba)
Boolean DrawRect(Integer x, Integer y, Integer width, Integer height, Integer rgba)

These functions are pretty obvious, except perhaps for the return values and the rgba argument.  Many of the 2D API drawing functions return a Boolean value indicating whether the call completed successfully.  The rgba argument is also common to many of the functions, and specifies the RGB color value as well as the alpha channel value to use when rendering the associated object.  For example, to draw a filled yellow filled rectangle at location (0,0) that is 100 pixels wide and 200 pixels high with 100% alpha, you would call DrawRect as follows:

screen.DrawRect(0, 0, 100, 200, &hFFFF00FF)

In our tic tac toe game, we use DrawRect and DrawLine calls to render the game grid, the focus rectangle that is drawn when a square is highlighted, and the ‘X’ used to mark the player’s move selections:

Function mark_selected_move(index as integer, useX as Boolean) as void
… ‘Code removed for simplicity
x = ((horz_line_sep) * index)+inset_x+line_width
y = inset_y + 10
w = horz_line_sep
h = vert_line_sep
screen.DrawLine(x, y, w+x-10, h+y-10, &h808080FF)
screen.DrawLine(x+horz_line_sep, y, x, h+y-10, &h808080FF)
…
End Function

This function defines the start and end points for two diagonal lines centered in the square in the game grid selected by the player.  These values are defined in terms of things like the vertical and horizontal distances between the game grid lines, as well as the width of those lines.  The essential point here is that the DrawLine function is used twice to mark the player’s move on the game screen.

Drawing Images

The BrightScript 2D API can also be used to draw images.  Images in JPG or PNG format can be rendered using the ifDraw2D interface DrawObject function:

Boolean DrawObject(Integer x, Integer y, Object src)

DrawObject renders the object specified by the src argument at the (x, y) location on the screen specified by the first two arguments.  src can be an roBitmap or an roRegion (a section of a bitmap.)  For example, to draw the image packaged with a channel in the location pkg:/images/myimage.png, you could use the following BrightScript code:

screen = CreateObject("roScreen")
img = CreateObject(“roBitmap”, “pkg:/images/myimage.png”)
screen.DrawObject(0, 0, img)
screen.Finish()

Our tic tac toe game uses this image rendering technique to draw a circle in game grid squares when the Roku Player makes a move. The 2D API does not include a function for drawing circles similar to DrawLine or DrawRect. Therefore in order to draw a circle to represent your opponent’s moves, we draw a PNG file packaged with the channel.

Drawing Text

The 2d API can also be used to draw text. The function used for this purpose is, you guessed it, DrawText:

Boolean DrawText(String text, Integer x, Integer y, Integer rgba, Object font)

text contains the string to draw, and font contains the font to use when rendering the text. rgba contains the color and alpha values to use. In our tic tac toe game, we use DrawText to announce the winner of the game, or to indicate that there was a tie:

As an example of how to use the DrawText API, here is how you could draw the text “Hello Roku” using the default device font:

fontRegistry = CreateObject("roFontRegistry")
font = fontRegistry.GetDefaultFont()
screen.DrawText(txt, 0, 0, &h00FFFFFF, font)
screen.Finish()

Note that drawing text is a very expensive operation and should be done sparingly.

More Information

More information about the 2D API can be found starting from the SDK documentation for the roScreen component at this link. The tic tac to sample game can be downloaded by clicking this link. Stay tuned for more articles on additional 2D graphics topics. In the meantime, have fun experimenting with Roku’s graphics features.

About Robert Burdick

Roku Developer Support Manager
This entry was posted in Uncategorized. Bookmark the permalink.