Drawing
The Drawing built-in functions give you full access to the display/LED-matrix. This is nice to have in most cases and becomes a requirement in some, like when creating video games.
Prerequisite
This lesson assumes you have completed the Built-in Function lesson.
Intro
We have been using the display so far using Print(). This lesson will take full control over the screen.
Graphical Memory
On computer systems, it is standard to handle all the “drawing” in memory, not on the display/monitor. Only when drawing elements of the memory is complete does the memory transfer to the display as a whole. Similar to the way our own brain works, we think about what we’re going to draw in our mind and then we draw it.
Even when clearing the screen, LcdClear() will only clear the graphics memory internally. This has no effect on the display. But then LcdShow() will transfer whatever is in the graphical memory to the screen.
Note how Print() updates the screen without Show(). This is because of extra code built into the Print() function to make it easier to use. However, this makes Print() slower than the other drawing functions. Once you have decided you will use the display API on this page, you should not use Print() with output forwarded to display to eliminate confusion.
Color Value
The system supports Color and B&W displays. To keep uniformity, 0 is always black and 1 is always white. Any other value is considered a standard RGB color formatted 0xRRGGBB. For example, GHI Electronics blue is 0x0977aa.
LcdClear(1) # White background
LcdCircle(0x0977aa,60,32,25) # Blue circle
LcdShow()
X and Y coordinates
X and Y coordinates inside code refers to an exact pixel location on the screen. This is often used to set the position of where something will appear on the screen.
Unlike vectors in math where x/y origin start at the lower left corner, computer graphics start at the top left corner.
With origin starting at the top left corner, X values run left to right starting at 0 on the very left., while Y values run top to bottom starting with 0 at the very top. This means the top left X and Y coordinate is 0,0. The BrainPad Pulse has 128 pixels across (X) by 64 pixels down (Y), making the bottom right corner 127,63 (remember 0 is the first pixel, not 1).
LcdShow()
This function will transfer the graphical memory to the display as explained above. All methods below only affect the graphical memory and do not affect the display at all.
LcdClear()
Clears the internal graphical memory, the framebuffer. You can either clear the screen to all black LcdClear(0) or all white LcdClear(1).
LcdClear(0)
LcdShow()
LcdCircle()
LcdCircle() generates a circle in memory, remember we must call LcdShow() to actually see the circle on the display. The LcdCircle(c, x, y, r) function requires 4 arguments: c for color, an x and y position on the display, and the r is the radius of the circle.
LcdClear(0)
LcdCircle(1,60,32,25)
LcdShow()
LcdLine()
LcdLine() does exactly as its name suggests. It creates a line from one point to another point. The LcdLine(c,x1, y1, x2, y2) function requires 4 arguments: c for color, the x and y starting position followed by the x and y finishing position. Like all other drawing methods you’ll still need to call LcdShow() to actually display the line on the screen.
LcdClear(0)
LcdLine(1,25,21,100,50)
LcdShow()
LcdText()
This is similar to the basic Print() function, but LcdText() gives you better control as to where the text is placed on the screen. The LcdText(“text”, c, x, y) function takes 4 arguments: first is the color, then text to be displayed followed by its x and y location on the screen. Unlike the Print() function , you’ll have to follow with the LcdShow() function to display.
LcdClear(0)
LcdText("Hello Brain",1,30,30)
LcdShow()
LcdText() first argument is always a string. If you need to print a number, you must first convert the number to a string using Str() function.
x = -10.99
LcdClear(0)
LcdText(Str(x),1,30,30)
LcdShow()
LcdTextS()
LcdTextS() function works like the LcdText() method except it adds scaling so you can make larger text or tall skinny text, depending on how you change the scale. The LcdTextS(“text”, c, x, y, scaleWidth, scaleHeight) function takes 6 arguments. The first three are exactly the same as the LcdText() function . The last two arguments set the scale width and scale height. Scale 1 is the standard size, 2 is double the size and so on.
LcdClear(0)
LcdTextS("Large Text",1,3,30,2,2)
LcdShow()
LcdRect()
The LcdRect() function Draws a rectangle on the screen. LcdRect(c,x, y, w, h) requires 5 arguments: c color, x coordinate, y coordinate, width, and then height.
LcdClear(0)
LcdRect(1,40,10,50,50);
LcdShow()
How do you draw a Rect() that sets a border on the very edges of the screen? If the display is 128×64 in size and the screen starts at 0x0, what would the last pixel be, 127×63 or 128×64?
LcdFill()
Works just like Rect() function, but this one will fill the area: LcdFill(c, x, y, w, h).
LcdClear(0)
LcdFill(1, 40, 10, 50, 50)
LcdShow()
This is also useful to clear part of the screen by setting color to black.
LcdPixel()
Draws a point (a pixel) on the screen. The LcdPixel() function requires 3 arguments. C for color, then the coordinate on the display.
LcdClear(0)
LcdPixel(1,64,32)
LcdShow()
You may have to look VERY closely to see the pixel on the screen. The BrainPad Pulse in particular has 8,192 of them that make up the entire screen, that is 128×64.
A single point is not much fun. We need to try something more interesting! Let’s get a random number to use as a random location on where the next point should be. We think you will like the results.
LcdClear(0)
@loop
x = Rnd(127)
y = Rnd(64)
LcdPixel(1, x, y)
LcdShow()
Goto loop
Inverting colors
Setting the display to all white and then draw black shapes can show some interesting results. The LcdFill() can also be used to fill a region with white area and then write black text.
LcdClear(0)
LcdFill(1, 15, 10, 100, 50)
LcdText("Hello World", 0, 30, 30)
LcdShow()
Moving Objects
Moving is done by clearing the screen and placing the object/shape at a new location. A circle can move on the x axis from 10 to 100 with 3 steps in each loop. Note that the LcdCircle() is NOT moving! Your eyes see it moving, but it is actually just a new circle that is getting drawn on a new location while clearing the old one.
For x = 10 to 100 step 3
LcdClear(0)
LcdCircle(1, x, 32, 10)
LcdShow()
Next
Remove the Clear() function from the code above and try again. What do you think the screen would look like?
LcdImg()
There are cases where images need to be added to the screen. Of course, we are taking about basic simple images, more like a tiny sprite in a game. Think 8bit and 80s here!
The image is an array of pixels. This arrays must start with 2 elements that contain the image’s width and height. We will place the array on multi line to help us visualize what the image might look like, but placing everything on a single line has the same effect. The second and third arguments are the sprite position on the screen. The last argument is transform.
Value | Transformation |
---|---|
0 | No transform |
1 | Flip image horizontally |
2 | Flip image vertically |
3 | Rotate the image 90 degrees |
4 | Rotate the image 180 degrees |
5 | Rotate the image 270 degrees (same as -90 degrees) |
Can you visualize what this code will produce before looking at the screen?
Dim a[2+(8*8)] = [8,8,
0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 1, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 1, 1, 0,
1, 1, 0, 1, 1, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 1, 0, 0, 1, 0, 0,
0, 1, 0, 1, 1, 0, 1, 0,
1, 0, 1, 0, 0, 1, 0, 1]
LcdClear(0)
LcdImg(a,60,30,0)
LcdShow()
Can you now move the Alien across the screen like we did with the LcdCircle()? Or make him show everywhere randomly?
LcdImgS()
This is identical to the previous function except it adds scaling to make the image larger, taller, or wider! LcdImgS(img, x, y, scaleWidth, scaleHeight, transform)
Dim a[2+(8*8)] = [8,8,
0, 0, 0, 1, 1, 0, 0, 0,
0, 0, 1, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 1, 1, 0,
1, 1, 0, 1, 1, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 1, 0, 0, 1, 0, 0,
0, 1, 0, 1, 1, 0, 1, 0,
1, 0, 1, 0, 0, 1, 0, 1]
LcdClear(0)
LcdImgS(a,60,30,2,2,0)
LcdShow()
Display Configuration
The internal software of any BrainPad microcomputer include support for graphics. Some include onboard displays for easy no-wiring option, like BrainPad Pulse for example. External displays can be wired as well.
B&W Displays
For B&W display, BrainPad supports SSD1309 I2C 128×64, similar to the one found on BrainPad pulse. An example display option is this plug-and-play option from Kitronik.
Those SSD1309 displays are also available in larger 2.42″ format. In this example, BrainPad Edge and BrainTronics are used to wire the display. Beside power, there are 2 wires that are needed. Those are the SDA and SCL pins that make up the I2C bus.
The only configuration needed for SSD1309 is its I2C address. It is typically 0x3C, but check your display’s documentation for the correct address.
LcdConfig(0, 0x3C)
LcdConfig(output, address) takes 2 arguments. The first one is to select the print-output selection. 0- only to console, 1- to display, 2 – both console and display. The second argument is the configuration. In the case of SSD1309, it is simply the I2C slave address of the connected display.
Color Displays
Support for color SPI displays includes ILI9342, ILI9341, and ST7735. These color displays only work on BrainPad boards with SC13 micro, such as BrainPad Pulse. The configuration for these displays includes many settings. Some settings are for selecting the control pins and others are for changing the display’s behavior.
This example configures BrainPad pulse to work with 1.8″ display board from Waveshare, which uses ST7735 1.8″ display. The display’s chip select is on pin 16 ands data control is on pin 12. There is also a backlight on pin 1 and reset on pin 8. More details on the LCD config are on the DUE Link website.
DWrite(1,1)# turn on the back-light
DWrite(8,1)# release reset
LcdConfig(0, (0x82<<0)|(16<<8)|(12<<14)|(1<<22))
LcdClear(0)
LcdTextS("BrainPad",0xf08000,35,0,2,3)
LcdTextS("has Color!!",0xf08000,22,95,2,3)
Dim a[2+(16*16)] = [16,16,
0, 0, 0, 0, 0, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0, 0, 0, 0,
0, 0, 0, 0, 0x542200, 0x542200, 0x542200, 0xEEDCAA, 0xEEDCAA, 0, 0xEEDCAA, 0, 0, 0, 0, 0,
0, 0, 0, 0x542200, 0xEEDCAA, 0x542200, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0, 0, 0,
0, 0, 0, 0x542200, 0xEEDCAA, 0x542200, 0x542200, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0, 0,
0, 0, 0, 0, 0x542200, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0, 0, 0, 0, 0,
0, 0, 0, 0,0x0044A9, 0x0044A9, 0xFF0000, 0x0044A9, 0x0044A9, 0xFF0000, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0x0044A9, 0x0044A9, 0x0044A9, 0xFF0000, 0x0044A9, 0x0044A9, 0xFF0000, 0x0044A9, 0x0044A9, 0x0044A9, 0, 0, 0,
0, 0, 0x0044A9, 0x0044A9, 0x0044A9, 0x0044A9, 0xFF0000, 0x0044A9, 0x0044A9, 0xFF0000, 0x0044A9, 0x0044A9, 0x0044A9, 0x0044A9, 0, 0,
0, 0, 0xEEDCAA, 0xEEDCAA, 0x0044A9, 0x0044A9, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0x0044A9, 0x0044A9, 0xEEDCAA, 0xEEDCAA, 0, 0,
0, 0, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0xFF0000, 0xFFDD00, 0xFF0000, 0xFF0000, 0xFFDD00, 0xFF0000, 0xEEDCAA, 0xEEDCAA, 0xEEDCAA, 0, 0,
0, 0, 0xEEDCAA, 0xEEDCAA, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xFF0000, 0xEEDCAA, 0, 0,
0, 0, 0, 0, 0xFF0000, 0xFF0000, 0xFF0000, 0, 0, 0xFF0000, 0xFF0000, 0xFF0000, 0, 0, 0, 0,
0, 0, 0, 0x542200, 0x542200,0x542200, 0, 0, 0, 0, 0x542200, 0x542200, 0x542200, 0, 0, 0,
0, 0, 0x542200, 0x542200,0x542200, 0x542200, 0, 0, 0, 0, 0x542200, 0x542200, 0x542200, 0x542200, 0, 0]
LcdImgS(a,60,35,3,3,0)
LcdShow()
What’s Next?
Draw on the screen, and have fun! Trying changing the different values inside the Line() function to see what kind of math art you can create.
LcdClear(0)
@loop
LcdLine(1, 0, 0, Rnd(127), Rnd(64))
LcdShow()
Goto loop
Try to put everything together from loops and variables. From here you can jump right to the Math Art lesson.
BrainStorm
Why do buttons on PC applications look similar? That is because Windows has a built-in “Button()” that developers typically use. Can you create a method that draws a “button”? Hint: This is nothing more than a LcdRect() with LcdText() in it.