PythonExtra/docs/sh/modgint-en.md

12 KiB

gint: Wrapper for the gint library

PythonExtra is developed with the fxSDK and uses the gint kernel as a runtime. The Python module gint provides access to gint's internal functions for rendering, keyboard, and more. Since gint has many versatile functions with good performance, it is beneficial to use it instead of e.g. casioplot or turtle.

The gint module tries to match its API with the original API of the C library, which is why few functions use keyword arguments or overloading. There are a few differences documented at the end of this document. For details not described in this document, one can refer to gint's header files which are always applicable unless this document explicitly says otherwise.

All constants, functions, etc. discussed here are in the gint module.

import gint
# or:
from gint import *

Keyboard input

Reference headers: <gint/keyboard.h> and <gint/keycodes.h>.

The module provides integer constants to refer to keyboard keys, with the following names:

KEY_F1 KEY_F2 KEY_F3 KEY_F4 KEY_F5 KEY_F6
KEY_SHIFT KEY_OPTN KEY_VARS KEY_MENU KEY_LEFT KEY_UP
KEY_ALPHA KEY_SQUARE KEY_POWER KEY_EXIT KEY_DOWN KEY_RIGHT
KEY_XOT KEY_LOG KEY_LN KEY_SIN KEY_COS KEY_TAN
KEY_FRAC KEY_FD KEY_LEFTP KEY_RIGHTP KEY_COMMA KEY_ARROW
KEY_7 KEY_8 KEY_9 KEY_DEL KEY_ACON
KEY_4 KEY_5 KEY_6 KEY_MUL KEY_DIV
KEY_1 KEY_2 KEY_3 KEY_ADD KEY_SUB
KEY_0 KEY_DOT KEY_EXP KEY_NEG KEY_EXE

Keyboard events

key_event:
  .time  -> int
  .mod   -> bool
  .shift -> bool
  .alpha -> bool
  .type  -> KEYEV_NONE | KEYEV_DOWN | KEYEV_UP | KEYEV_HOLD
  .key   -> KEY_*

gint communicates information about keyboard activity through events. Events indicate when a key (.key field) is pressed, repeated or released (.type field equal to KEYEV_DOWN, KEYEV_HOLD and KEYEV_UP respectively), when (.time field), and whether modifiers (SHIFT, .shift field, and ALPHA, .alpha field) where active at that time.

(The .mod field isn't very interesting, and the KEYEV_NONE value for the .type field is discussed later with pollevent().)

The functions getkey(), getkey_opt(), pollevent() and waitevent() all return events.

Waiting for a key press

getkey() -> key_event

The function getkey() pauses the program until a key is pressed or repeated, and returns the associated event (which is always of type KEYEV_DOWN or KEYEV_HOLD). By default, only arrow keys are repeated, once after 400 ms, then every 40 ms.

A few things can happen while getkey() is waiting. The user can press SHIFT or ALPHA which will trigger modifiers and affect the .shift and .alpha fields of the returned event. The user can also go to the main menu by pressing MENU or turn the calculator off with SHIFT+AC/ON.

Example. In a selection menu with N possible items, one could navigate with the up and down arrow keys, jump to the top or bottom with SHIFT up and SHIFT down, and validate with EXE.

ev = getkey()
if ev.key == KEY_EXE:
    pass       # Validate
elif ev.key == KEY_UP and ev.shift:
    pos = 0    # Jump to top
elif ev.key == KEY_DOWN and ev.shift:
    pos = N-1  # Jump to bottom
elif ev.key == KEY_UP and pos > 0:
    pos -= 1   # Move one place up
elif ev.key == KEY_DOWN and pos < N-1:
    pos += 1   # Move one place down

TODO: Mention getkey_opt()

Reading keyboard events in real time

pollevent() -> key_event
waitevent() -> key_event
clearevents() -> None

gint records keyboard activity in the background while the program is running. Events are placed in a queue until the program reads them. This is how getkey() learns about keyboard activity, for example.

The pollevent() function provides direct access to events. pollevent() returns the oldest event that hasn't yet been read by the program. If there are no events waiting to be read, pollevent() returns a "fake" event with type KEYEV_NONE to indicate that the queue is empty.

Since pollevent() returns instantly, it can be used to read keyboard activity without pausing the program.

Example. A game loop could, at every frame, read all pending events to determine when the player pressed the SHIFT key (in this example the "action" key) to perform an action.

# Render game...

while True:
    ev = pollevent()
    if ev.type == KEYEV_NONE:
        break  # We're done reading events
    if ev.type == KEYEV_DOWN and ev.key == KEY_SHIFT:
        pass   # The SHIFT key was just pressed!
    # Implicitly ignores other keys

# Simulate game...

The waitevent() function operates similarly, but if there are no pending events it waits for something to happen before returning. It is used quite rarely because in waiting situations one usually uses getkey() instead.

The function clearevents() reads and ignores all events, i.e. it "throws away" all the information about recent keyboard activity. It is useful to know the immediate state of the keyboard with keydown()' (see below). clearevents() is equivalent to the following definition:

def clearevents():
    ev = pollevent()
    while ev.type != KEYEV_NONE:
        ev = pollevent()

Reading the immediate state of the keyboard

keydown(key: int) -> bool
keydown_all(*keys: [int]) -> bool
keydown_any(*keys: [int]) -> bool

After events have been read and the event queue is empty, one can query the immediate state of keys with the keydown() function. keydown(k) returns True if key k is currently pressed, False otherwise. This function only works after events have been read, which is usually done either with pollevent() or with clearevents().

Example. A game loop could check the state of the left/right keys at every frame to move the player.

while True:
    ev = pollevent()
    # ... same thing as the pollevent() example

if keydown(KEY_LEFT):
    player_x -= 1
if keydown(KEY_RIGHT):
    player_x += 1

keydown_all() takes a series of keys as parameters and returns True if they are all pressed. keydown_any() is similar and returns True if at least one of the listed keys is pressed.

Quickly querying key state changes

cleareventflips() -> None
keypressed(key: int) -> bool
keyreleased(key: int) -> bool

keydown() only tells whether keys are pressed at a given time; it cannot be used to check when keys change from the released state to the pressed state or the other way around. To do this, one must either read individual events (which can be annoying) or use the functions described below.

keypressed(k) and keyreleased(k) indicate whether key k was pressed/released since the last call to cleareventflips(). Be careful, here "pressed/released" should be interpreted as "indicated pressed/released by events read" not as a real-time state change.

Example. A game loop could test both the immediate state of some keys and state changes forother keys by using immediate functions after cleareventflips() followed by clearevents().

# Render game...

cleareventflips()
clearevents()

if keypressed(KEY_SHIFT):
    pass # Action !
if keydown(KEY_LEFT):
    player_x -= 1
if keydown(KEY_RIGHT):
    player_x += 1

# Simulate game...

Miscellaneous keyboard functions

keycode_function(key: int) -> int
keycode_digit(key: int) -> int

keycode_function(k) returns the F-key number if k (i.e. 1 for KEY_F1, 2 for KEY_F2, etc.) and -1 for other keys.

keycode_digit(k) returns the digit associated with k (i.e. 0 for KEY_0, 1 for KEY_1, etc.) and -1 for other keys.

Drawing and rendering

Reference headers: <gint/display.h>, and for some details <gint/display-fx.h> and <gint/display-cg.h>.

Color manipulation

C_WHITE: int    # White
C_BLACK: int    # Black
C_LIGHT: int    # Light gray (on B&W: gray engine)
C_DARK: int     # Dark gray (on B&W: gray engine)
C_NONE: int     # Transparent
C_INVERT: int   # Function: inverse

# Black-and-white (B&W) models only:
C_LIGHTEN: int  # Function: lighten (gray engine)
C_DARKEN: int   # Function: darken (gray engine)

# fx-CG models only:
C_RED: int      # Pure red
C_GREEN: int    # Pure green
C_BLUE: int     # Pure blue
C_RGB(r: int, g: int, b: int) -> int

Colors are all integers (manipulating (r,g,b) tuples is excruciatingly slow and requires memory allocations all over the place). A few default colors are provided.

On the fx-CG series, the C_RGB() function can be used to create colors from three components ranging from 0 to 31.

TODO: Explain the gray engine.

Basic rendering functions

DWIDTH: int
DHEIGHT: int
dupdate() -> None
dclear(color: int) -> None
dpixel(x: int, y: int, color: int) -> None
dgetpixel(x: int, y: int) -> int

The integers DWIDTH and DHEIGHT indicate the screen's dimensions. The screen is 128x64 on black-and-white models (like the G-III) and 396x224 on the fx-CG series (the full screen is available).

All rendering functions draw to an internal image called the "VRAM"; rendering calls are thus not immediate visible on the screen. For the result to be visible one must call the dupdate() function, which transfers the contents of the VRAM to the real display. Usually, this is done after rendering everything we need on one frame instead of after each drawing function call.

In PythonExtra, dupdate() also indicates a "switch to graphics mode". Due to certain optimizations any call to print() is considered a "switch to text mode", and while in text mode the shell might redraw at any time. In order to draw after using text mode, one must call dupdate() to force a switch to graphics mode before starting rendering. Otherwise the shell and program might render at the same time and produce incoherent results.

dclear() fills the screen with a uniform color.

dpixel() changes a pixel's color. Coordinates are universally (x,y) where x is in the range 0 to DWIDTH-1 inclusive (0 being left) and y is in the range 0 to DHEIGHT-1 inclusive (0 being top).

dgetpixel() returns the color of a pixel. Note that dgetpixel() reads from VRAM, not from the display.

Geometric shape rendering functions

TODO

Image rendering functions

TODO

Differences with gint's C API

  • dsubimage() doesn't have its final parameter int flags. The flags are only minor optimizations and could be removed in future gint versions.
  • Image constructorsimage() and image_<format>() don't exist in the C API.
  • Asynchronous volatile-flag-based timeouts are replaced with synchronous millisecond delays (integer value or None).

TODO: There are more.