- TI-84+CE Hardware Cursor
- 09 Nov 2019 04:09:33 pm
- Last edited by commandblockguy on 26 Jan 2022 12:40:24 pm; edited 1 time in total
The LCD controller that the CE uses includes a hardware cursor that can display a cursor on screen without having to redraw the cursor each time the screen is updated. It was previously (by Mateo, at least) thought to be impossible to use on the CE due to the wonky way that the CE's LCD is set up, but I've found a way to use it.
The hardware cursor uses either a 64x64 or a selection of one of four 32x32 pixel images. Each pixel can have one of two palette colors or be either transparent or the inverse of whatever pixel would otherwise be onscreen.
For more info on the capabilities of the cursor, consult the datasheet for the PL111 LCD controller.
For the cursor to work, the clocks-per-line needs to be set to 320 rather than the default 240.
Here's some code to enable the cursor and move it around with the arrow keys:
Code:
I've also written a converter (in like 15 minutes, don't judge) for PNG images into the format that the PL111 expects.
Code:
The last line only works on Linux and converts the binary into a C file. Windows probably has an equivalent. The input image should use black for palette 0, white for palette 1, transparent for transparency, and any other color for inverted transparency.
And now for some eye candy:
As for the practical uses of this, I imagine it could be useful for moving a cursor around an image that is expensive to redraw (as in Mahjong CE), for inverting colors, or to add an overlay to the OS in an extremely lazy way.
The hardware cursor uses either a 64x64 or a selection of one of four 32x32 pixel images. Each pixel can have one of two palette colors or be either transparent or the inverse of whatever pixel would otherwise be onscreen.
For more info on the capabilities of the cursor, consult the datasheet for the PL111 LCD controller.
For the cursor to work, the clocks-per-line needs to be set to 320 rather than the default 240.
Here's some code to enable the cursor and move it around with the arrow keys:
Code:
#define lcd_CrsrImage ((uint32_t*)0xE30800)
#define lcd_CrsrImageLen 256
#define lcd_CrsrCtrl (*(uint32_t*)0xE30C00)
#define lcd_CrsrConfig (*(uint32_t*)0xE30C04)
#define lcd_CrsrPalette0 (*(uint32_t*)0xE30C08)
#define lcd_CrsrPalette1 (*(uint32_t*)0xE30C0C)
#define lcd_CrsrXY (*(uint32_t*)0xE30C10)
#define lcd_CrsrX (*(uint16_t*)0xE30C10)
#define lcd_CrsrY (*(uint16_t*)0xE30C12)
#define lcd_CrsrClip (*(uint32_t*)0xE30C04)
extern unsigned char cursor_bin[256];
void main(void) {
uint16_t x = 0, y = 0;
// set the CPL
lcd_Timing2 = (uint32_t)(lcd_Timing2 & ~(uint32_t)0x03FF0000) | (uint32_t)(LCD_WIDTH - 1) << 16;
memcpy(lcd_CrsrImage, cursor_bin, 256); // set cursor image
lcd_CrsrConfig = 0; // select 32x32, image0
lcd_CrsrPalette0 = 0x00000000; // set black palette color
lcd_CrsrPalette1 = 0x00FFFFFF; // set white palette color
lcd_CrsrXY = 0; // reset cursor position
lcd_CrsrClip = 0; // reset clipping
lcd_CrsrCtrl = 1; // enable cursor
while(!kb_IsDown(kb_KeyClear)) {
kb_Scan();
if(kb_IsDown(kb_KeyLeft)) x--;
if(kb_IsDown(kb_KeyRight)) x++;
if(kb_IsDown(kb_KeyUp)) y--;
if(kb_IsDown(kb_KeyDown)) y++;
lcd_CrsrX = x; // update the position of the cursor
lcd_CrsrY = y;
}
lcd_CrsrCtrl = 0; // disable cursor
// reset CPL
lcd_Timing2 = (uint32_t)(lcd_Timing2 & ~(uint32_t)0x03FF0000) | (uint32_t)(LCD_HEIGHT - 1) << 16;
}
I've also written a converter (in like 15 minutes, don't judge) for PNG images into the format that the PL111 expects.
Code:
import png, os
from itertools import zip_longest
def grouper(n, iterable, fillvalue=None):
args = [iter(iterable)] * n
return zip_longest(fillvalue=fillvalue, *args)
f=open('cursor.png', 'rb')
r = png.Reader(file=f)
i = r.read()[2]
val = 0
length = 0
out = bytearray()
for row in i:
for r,g,b,a in grouper(4, row):
if a == 0:
bits = 0b10
elif (r,g,b)==(0,0,0):
bits = 0b00
elif (r,g,b)==(255,255,255):
bits = 0b01
else:
bits = 0b11
val = val << 2 | bits
length += 2
if length == 8:
out.append(val)
length = 0
val = 0
outfile = open('cursor.bin', 'wb')
outfile.write(out)
outfile.close()
os.system('xxd -i cursor.bin > cursor.c')
The last line only works on Linux and converts the binary into a C file. Windows probably has an equivalent. The input image should use black for palette 0, white for palette 1, transparent for transparency, and any other color for inverted transparency.
And now for some eye candy:
As for the practical uses of this, I imagine it could be useful for moving a cursor around an image that is expensive to redraw (as in Mahjong CE), for inverting colors, or to add an overlay to the OS in an extremely lazy way.