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:

#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)) {
        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.

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 =[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
         bits = 0b11

      val = val << 2 | bits
      length += 2
      if length == 8:
         length = 0
         val = 0

outfile = open('cursor.bin', 'wb')

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.
Very nice work - this could definitely come in handy for many things.
This is incredibly awesome- it will be nice to see this used to speed up programs.

I imagine this is quite fast- is there a comparison between previous cursor implementations and this method in an actual game?
Can this be coded in on-calc assembly?
Yes. You could also do this in ICE using the pointers given in the #define directives.
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum