260 lines
8.3 KiB
C
260 lines
8.3 KiB
C
// Visual keyboard + mouse demo: one square per JoeyKeyE, lit when its
|
|
// key is held, and a small pointer drawn at the live mouse position.
|
|
// Holding the left mouse button while the pointer is over a cell lights
|
|
// it as if the corresponding key were down. Press ESC to quit.
|
|
//
|
|
// The render loop only redraws cells whose target lit state changed
|
|
// since last frame -- so on idle frames, the only work is the cursor
|
|
// erase + redraw + a tiny rect-present pair. The cursor erase is
|
|
// implemented by redrawing the cell that contained the *previous*
|
|
// cursor position; in the gap regions between cells the cursor will
|
|
// briefly leave a trail until that cell is touched again, which is an
|
|
// acceptable demo-quality compromise.
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <joey/joey.h>
|
|
|
|
#define GRID_COLS 10
|
|
#define GRID_ROWS 6
|
|
#define CELL_W 28
|
|
#define CELL_H 28
|
|
#define GAP 4
|
|
#define MARGIN_X 2
|
|
#define MARGIN_Y 6
|
|
|
|
#define CURSOR_W 4
|
|
#define CURSOR_H 4
|
|
|
|
#define COLOR_BACKGROUND 0
|
|
#define COLOR_UNLIT 1
|
|
#define COLOR_LIT 2
|
|
#define COLOR_CURSOR 3
|
|
|
|
#define CELL_NONE ((int16_t)-1)
|
|
|
|
static void buildPalette(SurfaceT *screen);
|
|
static void cellAtPoint(int16_t px, int16_t py, int16_t *outCol, int16_t *outRow);
|
|
static bool cellTargetLit(int16_t col, int16_t row, int16_t cursorCol, int16_t cursorRow);
|
|
static void drawCell(SurfaceT *screen, int16_t col, int16_t row, bool lit);
|
|
static void drawCursor(SurfaceT *screen, int16_t x, int16_t y);
|
|
static void initialPaint(SurfaceT *screen);
|
|
static void presentChangedCells(SurfaceT *screen, int16_t cursorCol, int16_t cursorRow);
|
|
static void updateCursor(SurfaceT *screen, int16_t cursorCol, int16_t cursorRow);
|
|
|
|
// Keys laid out row-by-row. KEY_NONE cells stay blank. Shape roughly
|
|
// resembles a real keyboard (top number row, then QWERTY rows, then a
|
|
// cluster of modifiers / arrows / function keys).
|
|
static const JoeyKeyE gKeyGrid[GRID_ROWS][GRID_COLS] = {
|
|
{ KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0 },
|
|
{ KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P },
|
|
{ KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, KEY_BACKSPACE },
|
|
{ KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_LSHIFT, KEY_RSHIFT, KEY_TAB },
|
|
{ KEY_SPACE, KEY_ESCAPE, KEY_RETURN, KEY_LCTRL, KEY_LALT, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_NONE },
|
|
{ KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10 }
|
|
};
|
|
|
|
static bool gCellLit[GRID_ROWS][GRID_COLS];
|
|
static int16_t gLastCursorX = -100;
|
|
static int16_t gLastCursorY = -100;
|
|
static int16_t gLastCursorCol = CELL_NONE;
|
|
static int16_t gLastCursorRow = CELL_NONE;
|
|
|
|
|
|
static void buildPalette(SurfaceT *screen) {
|
|
uint16_t colors[SURFACE_COLORS_PER_PALETTE];
|
|
uint16_t i;
|
|
|
|
for (i = 0; i < SURFACE_COLORS_PER_PALETTE; i++) {
|
|
colors[i] = 0x0000;
|
|
}
|
|
colors[COLOR_BACKGROUND] = 0x0000; // black
|
|
colors[COLOR_UNLIT] = 0x0333; // dark gray
|
|
colors[COLOR_LIT] = 0x00F0; // bright green
|
|
colors[COLOR_CURSOR] = 0x0FFF; // white
|
|
|
|
paletteSet(screen, 0, colors);
|
|
}
|
|
|
|
|
|
static void cellAtPoint(int16_t px, int16_t py, int16_t *outCol, int16_t *outRow) {
|
|
int16_t col;
|
|
int16_t row;
|
|
int16_t cx;
|
|
int16_t cy;
|
|
|
|
*outCol = CELL_NONE;
|
|
*outRow = CELL_NONE;
|
|
for (row = 0; row < GRID_ROWS; row++) {
|
|
for (col = 0; col < GRID_COLS; col++) {
|
|
cx = (int16_t)(MARGIN_X + col * (CELL_W + GAP));
|
|
cy = (int16_t)(MARGIN_Y + row * (CELL_H + GAP));
|
|
if (px >= cx && px < (cx + CELL_W) && py >= cy && py < (cy + CELL_H)) {
|
|
*outCol = col;
|
|
*outRow = row;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static bool cellTargetLit(int16_t col, int16_t row, int16_t cursorCol, int16_t cursorRow) {
|
|
JoeyKeyE key;
|
|
|
|
key = gKeyGrid[row][col];
|
|
if (key == KEY_NONE) {
|
|
return false;
|
|
}
|
|
if (joeyKeyDown(key)) {
|
|
return true;
|
|
}
|
|
if (col == cursorCol && row == cursorRow && joeyMouseDown(MOUSE_BUTTON_LEFT)) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
static void drawCell(SurfaceT *screen, int16_t col, int16_t row, bool lit) {
|
|
int16_t x;
|
|
int16_t y;
|
|
uint8_t color;
|
|
|
|
x = (int16_t)(MARGIN_X + col * (CELL_W + GAP));
|
|
y = (int16_t)(MARGIN_Y + row * (CELL_H + GAP));
|
|
color = lit ? COLOR_LIT : COLOR_UNLIT;
|
|
fillRect(screen, x, y, CELL_W, CELL_H, color);
|
|
}
|
|
|
|
|
|
static void drawCursor(SurfaceT *screen, int16_t x, int16_t y) {
|
|
fillRect(screen, x, y, CURSOR_W, CURSOR_H, COLOR_CURSOR);
|
|
}
|
|
|
|
|
|
static void initialPaint(SurfaceT *screen) {
|
|
int16_t col;
|
|
int16_t row;
|
|
JoeyKeyE key;
|
|
|
|
surfaceClear(screen, COLOR_BACKGROUND);
|
|
for (row = 0; row < GRID_ROWS; row++) {
|
|
for (col = 0; col < GRID_COLS; col++) {
|
|
key = gKeyGrid[row][col];
|
|
if (key == KEY_NONE) {
|
|
continue;
|
|
}
|
|
drawCell(screen, col, row, false);
|
|
gCellLit[row][col] = false;
|
|
}
|
|
}
|
|
surfacePresent(screen);
|
|
}
|
|
|
|
|
|
static void presentChangedCells(SurfaceT *screen, int16_t cursorCol, int16_t cursorRow) {
|
|
int16_t col;
|
|
int16_t row;
|
|
JoeyKeyE key;
|
|
bool lit;
|
|
int16_t x;
|
|
int16_t y;
|
|
|
|
for (row = 0; row < GRID_ROWS; row++) {
|
|
for (col = 0; col < GRID_COLS; col++) {
|
|
key = gKeyGrid[row][col];
|
|
if (key == KEY_NONE) {
|
|
continue;
|
|
}
|
|
lit = cellTargetLit(col, row, cursorCol, cursorRow);
|
|
if (lit == gCellLit[row][col]) {
|
|
continue;
|
|
}
|
|
drawCell(screen, col, row, lit);
|
|
x = (int16_t)(MARGIN_X + col * (CELL_W + GAP));
|
|
y = (int16_t)(MARGIN_Y + row * (CELL_H + GAP));
|
|
surfacePresentRect(screen, x, y, CELL_W, CELL_H);
|
|
gCellLit[row][col] = lit;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Erase the previous cursor (by redrawing the cell that held it) and
|
|
// stamp the new cursor at the current mouse position. Both rects are
|
|
// presented; if the cursor stayed inside the same cell only one rect
|
|
// pair is touched, so steady-state cost is small.
|
|
static void updateCursor(SurfaceT *screen, int16_t cursorCol, int16_t cursorRow) {
|
|
int16_t mouseX;
|
|
int16_t mouseY;
|
|
|
|
mouseX = joeyMouseX();
|
|
mouseY = joeyMouseY();
|
|
|
|
if (gLastCursorX != mouseX || gLastCursorY != mouseY) {
|
|
if (gLastCursorCol != CELL_NONE) {
|
|
drawCell(screen, gLastCursorCol, gLastCursorRow, gCellLit[gLastCursorRow][gLastCursorCol]);
|
|
surfacePresentRect(screen,
|
|
(int16_t)(MARGIN_X + gLastCursorCol * (CELL_W + GAP)),
|
|
(int16_t)(MARGIN_Y + gLastCursorRow * (CELL_H + GAP)),
|
|
CELL_W, CELL_H);
|
|
} else if (gLastCursorX >= 0 && gLastCursorY >= 0) {
|
|
// Old cursor was in a gap region. Stamp background over it.
|
|
fillRect(screen, gLastCursorX, gLastCursorY, CURSOR_W, CURSOR_H, COLOR_BACKGROUND);
|
|
surfacePresentRect(screen, gLastCursorX, gLastCursorY, CURSOR_W, CURSOR_H);
|
|
}
|
|
}
|
|
|
|
drawCursor(screen, mouseX, mouseY);
|
|
surfacePresentRect(screen, mouseX, mouseY, CURSOR_W, CURSOR_H);
|
|
|
|
gLastCursorX = mouseX;
|
|
gLastCursorY = mouseY;
|
|
gLastCursorCol = cursorCol;
|
|
gLastCursorRow = cursorRow;
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
JoeyConfigT config;
|
|
SurfaceT *screen;
|
|
int16_t cursorCol;
|
|
int16_t cursorRow;
|
|
|
|
config.hostMode = HOST_MODE_TAKEOVER;
|
|
config.codegenBytes = 8 * 1024;
|
|
config.maxSurfaces = 4;
|
|
config.audioBytes = 64 * 1024;
|
|
config.assetBytes = 128 * 1024;
|
|
|
|
if (!joeyInit(&config)) {
|
|
fprintf(stderr, "joeyInit failed: %s\n", joeyLastError());
|
|
return 1;
|
|
}
|
|
|
|
screen = surfaceGetScreen();
|
|
if (screen == NULL) {
|
|
fprintf(stderr, "surfaceGetScreen returned NULL\n");
|
|
joeyShutdown();
|
|
return 1;
|
|
}
|
|
|
|
buildPalette(screen);
|
|
scbSetRange(screen, 0, SURFACE_HEIGHT - 1, 0);
|
|
initialPaint(screen);
|
|
joeyInputPoll();
|
|
|
|
for (;;) {
|
|
joeyInputPoll();
|
|
if (joeyKeyPressed(KEY_ESCAPE)) {
|
|
break;
|
|
}
|
|
cellAtPoint(joeyMouseX(), joeyMouseY(), &cursorCol, &cursorRow);
|
|
presentChangedCells(screen, cursorCol, cursorRow);
|
|
updateCursor(screen, cursorCol, cursorRow);
|
|
}
|
|
|
|
joeyShutdown();
|
|
return 0;
|
|
}
|