Demo Stage Kaleido
Source: src/demo_stage_kaleido.c · 127 lines · 6 functions.
Module entry points
These functions are exposed to the rest of the project. Open one to follow its decisions and the helpers it calls.
How to read these diagrams
Each function has its own expandable diagram using the actual expressions and statements from this file. Decisions split into True and False; loop bodies are indented. Returns end the function immediately; break and continue follow their C meanings. Arrows between statements show their order when execution reaches them.
These are structural source diagrams before preprocessing, not runtime traces. Conditional compilation and macros remain source expressions. Ternary choices remain inside their statement. Calls are linked separately; callback execution and task scheduling are not inferred.
Functions in this file
setStageEightCell() · source line 43
static void setStageEightCell(int column, int row, uint8_t glyph)
- Decision
column < 0 || column >= DEMO_STAGE_EIGHT_COLUMNS || row < 0 || row >= DEMO_STAGE_EIGHT_ROWSTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
stage_eight_cells[(size_t)row * DEMO_STAGE_EIGHT_COLUMNS + (size_t)column] = glyph;
Read original function source
static void setStageEightCell(int column, int row, uint8_t glyph)
{
if (column < 0 || column >= DEMO_STAGE_EIGHT_COLUMNS ||
row < 0 || row >= DEMO_STAGE_EIGHT_ROWS) return;
stage_eight_cells[(size_t)row * DEMO_STAGE_EIGHT_COLUMNS + (size_t)column] = glyph;
}addStageEightRing() · source line 50
static void addStageEightRing(uint8_t radius)
Calls into this documentation:
- FOR loop
uint8_t offset = 0U; offset <= radius; ++offsetRepeat body while the loop condition permits; then continue below.
- Execute
const uint8_t glyph = offset == radius ? stage_eight_glyphs[0U] : stage_eight_glyphs[1U + (offset - 1U) % (DEMO_STAGE_EIGHT_GLYPH_COUNT - 1U)]; - Execute
const int wide = (int)radius; - Execute
const int narrow = (int)offset; - Execute
const int centre_x = DEMO_STAGE_EIGHT_CENTRE_COLUMN; - Execute
const int centre_y = DEMO_STAGE_EIGHT_CENTRE_ROW; - Execute
setStageEightCell(centre_x + wide, centre_y + narrow, glyph); - Execute
setStageEightCell(centre_x + wide, centre_y - narrow, glyph); - Execute
setStageEightCell(centre_x - wide, centre_y + narrow, glyph); - Execute
setStageEightCell(centre_x - wide, centre_y - narrow, glyph); - Execute
setStageEightCell(centre_x + narrow, centre_y + wide, glyph); - Execute
setStageEightCell(centre_x + narrow, centre_y - wide, glyph); - Execute
setStageEightCell(centre_x - narrow, centre_y + wide, glyph); - Execute
setStageEightCell(centre_x - narrow, centre_y - wide, glyph);
Read original function source
static void addStageEightRing(uint8_t radius)
{
// BASIC lines 210-280 choose one point in an octant, then write its eight
// reflected partners. R(0) marks the outer points; the remaining selected
// PET glyphs fill toward the axes, echoing the BASIC subroutine at line 900.
for (uint8_t offset = 0U; offset <= radius; ++offset) {
const uint8_t glyph = offset == radius ? stage_eight_glyphs[0U] :
stage_eight_glyphs[1U + (offset - 1U) % (DEMO_STAGE_EIGHT_GLYPH_COUNT - 1U)];
const int wide = (int)radius;
const int narrow = (int)offset;
const int centre_x = DEMO_STAGE_EIGHT_CENTRE_COLUMN;
const int centre_y = DEMO_STAGE_EIGHT_CENTRE_ROW;
setStageEightCell(centre_x + wide, centre_y + narrow, glyph);
setStageEightCell(centre_x + wide, centre_y - narrow, glyph);
setStageEightCell(centre_x - wide, centre_y + narrow, glyph);
setStageEightCell(centre_x - wide, centre_y - narrow, glyph);
setStageEightCell(centre_x + narrow, centre_y + wide, glyph);
setStageEightCell(centre_x + narrow, centre_y - wide, glyph);
setStageEightCell(centre_x - narrow, centre_y + wide, glyph);
setStageEightCell(centre_x - narrow, centre_y - wide, glyph);
}
}beginStageEightPattern() · source line 74
static void beginStageEightPattern(uint32_t now_ms)
Calls into this documentation:
- Execute
memset(stage_eight_cells, 0, sizeof(stage_eight_cells)); - FOR loop
size_t glyph = 0U; glyph < DEMO_STAGE_EIGHT_GLYPH_COUNT; ++glyphRepeat body while the loop condition permits; then continue below.
- Execute
uint8_t character = DEMO_STAGE_EIGHT_GRAPHIC_FIRST + (uint8_t)(esp_random() % DEMO_STAGE_EIGHT_GRAPHIC_COUNT); - Decision
esp_random() % 100U < DEMO_STAGE_EIGHT_REVERSE_PERCENTTrue- Execute
character |= 0x80U;
FalseContinue after this decision.
- Execute
stage_eight_glyphs[glyph] = character;
- Execute
stage_eight_next_radius = 1U; - Execute
stage_eight_holding = false; - Execute
addStageEightRing(stage_eight_next_radius++); - Execute
stage_eight_next_ring_at = now_ms + DEMO_STAGE_EIGHT_RING_MS;
Read original function source
static void beginStageEightPattern(uint32_t now_ms)
{
memset(stage_eight_cells, 0, sizeof(stage_eight_cells));
for (size_t glyph = 0U; glyph < DEMO_STAGE_EIGHT_GLYPH_COUNT; ++glyph) {
uint8_t character = DEMO_STAGE_EIGHT_GRAPHIC_FIRST +
(uint8_t)(esp_random() % DEMO_STAGE_EIGHT_GRAPHIC_COUNT);
// A high bit selects PET reverse video: black figure on a white cell.
if (esp_random() % 100U < DEMO_STAGE_EIGHT_REVERSE_PERCENT) character |= 0x80U;
stage_eight_glyphs[glyph] = character;
}
stage_eight_next_radius = 1U;
stage_eight_holding = false;
addStageEightRing(stage_eight_next_radius++);
stage_eight_next_ring_at = now_ms + DEMO_STAGE_EIGHT_RING_MS;
}demoStageKaleidoStart() · source line 90
void demoStageKaleidoStart(uint32_t now_ms)
Calls into this documentation:
- Execute
beginStageEightPattern(now_ms);
Read original function source
void demoStageKaleidoStart(uint32_t now_ms)
{
beginStageEightPattern(now_ms);
}demoStageKaleidoUpdate() · source line 95
void demoStageKaleidoUpdate(uint32_t now_ms)
Calls into this documentation:
- Decision
stage_eight_holdingTrue- Decision
(int32_t)(now_ms - stage_eight_hold_until) >= 0True- Execute
beginStageEightPattern(now_ms);
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
(int32_t)(now_ms - stage_eight_next_ring_at) < 0True- Exit this function
return;
FalseContinue after this decision.
- Execute
addStageEightRing(stage_eight_next_radius++); - Execute
stage_eight_next_ring_at += DEMO_STAGE_EIGHT_RING_MS; - Decision
stage_eight_next_radius > DEMO_STAGE_EIGHT_MAX_RADIUSTrue- Execute
stage_eight_holding = true; - Execute
stage_eight_hold_until = now_ms + DEMO_STAGE_EIGHT_HOLD_MS;
FalseContinue after this decision.
Read original function source
void demoStageKaleidoUpdate(uint32_t now_ms)
{
if (stage_eight_holding) {
if ((int32_t)(now_ms - stage_eight_hold_until) >= 0) beginStageEightPattern(now_ms);
return;
}
if ((int32_t)(now_ms - stage_eight_next_ring_at) < 0) return;
addStageEightRing(stage_eight_next_radius++);
stage_eight_next_ring_at += DEMO_STAGE_EIGHT_RING_MS;
if (stage_eight_next_radius > DEMO_STAGE_EIGHT_MAX_RADIUS) {
stage_eight_holding = true;
stage_eight_hold_until = now_ms + DEMO_STAGE_EIGHT_HOLD_MS;
}
}demoStageKaleidoDraw() · source line 111
void demoStageKaleidoDraw(uint16_t *frame)
Calls into this documentation:
- FOR loop
int row = 0; row < DEMO_STAGE_EIGHT_ROWS; ++rowRepeat body while the loop condition permits; then continue below.
- FOR loop
int column = 0; column < DEMO_STAGE_EIGHT_COLUMNS; ++columnRepeat body while the loop condition permits; then continue below.
- Execute
const uint8_t glyph = stage_eight_cells[(size_t)row * DEMO_STAGE_EIGHT_COLUMNS + (size_t)column]; - Decision
glyph == 0UTrue- Next loop iteration
continue;
FalseContinue after this decision.
- Execute
drawPet2001Char(frame, column * (int)PET2001_FONT_GLYPH_WIDTH, row * (int)PET2001_FONT_GLYPH_HEIGHT, glyph, DEMO_STAGE_EIGHT_FOREGROUND, COLOR_BLACK, 1);
Read original function source
void demoStageKaleidoDraw(uint16_t *frame)
{
// The working cells already contain normal or reverse PET display codes.
// Draw only nonzero cells over Demo's black-cleared background. Rows 19
// and 20 stay clear for the normal scale-two bottom ticker.
for (int row = 0; row < DEMO_STAGE_EIGHT_ROWS; ++row) {
for (int column = 0; column < DEMO_STAGE_EIGHT_COLUMNS; ++column) {
const uint8_t glyph = stage_eight_cells[(size_t)row *
DEMO_STAGE_EIGHT_COLUMNS +
(size_t)column];
if (glyph == 0U) continue;
drawPet2001Char(frame, column * (int)PET2001_FONT_GLYPH_WIDTH,
row * (int)PET2001_FONT_GLYPH_HEIGHT, glyph,
DEMO_STAGE_EIGHT_FOREGROUND, COLOR_BLACK, 1);
}
}
}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "demo_stage_kaleido.h"
#include "PET2001_font.h"
#include "esp_attr.h"
#include "esp_random.h"
#include "game_graphics.h"
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
// Segment 8 -- KALEIDO, a PET 2001 black-and-white character display. The
// original program used a 40 x 25 screen. Demo's bottom ticker uses two rows,
// so this stage stays within the remaining upper 40 x 19 PET cells.
#define DEMO_STAGE_EIGHT_COLUMNS 40
#define DEMO_STAGE_EIGHT_ROWS 19
#define DEMO_STAGE_EIGHT_CENTRE_COLUMN 19
#define DEMO_STAGE_EIGHT_CENTRE_ROW 9
#define DEMO_STAGE_EIGHT_MAX_RADIUS 8U
// BASIC lines 135/160 choose codes 65 through 127. Half become reverse-video
// cells, matching line 165. Change these values to experiment with PET glyphs.
#define DEMO_STAGE_EIGHT_GRAPHIC_FIRST 65U
#define DEMO_STAGE_EIGHT_GRAPHIC_COUNT 63U
#define DEMO_STAGE_EIGHT_REVERSE_PERCENT 50U
#define DEMO_STAGE_EIGHT_GLYPH_COUNT 7U
// One reflected ring appears every interval. The completed pattern remains on
// screen before a new random seven-glyph palette starts, like BASIC line 795.
#define DEMO_STAGE_EIGHT_RING_MS 180U
#define DEMO_STAGE_EIGHT_HOLD_MS 3000U
#define DEMO_STAGE_EIGHT_FOREGROUND COLOR_WHITE
// The active ticker-safe 40 x 19 PET pattern and its seven random source glyphs
// live in PSRAM. A zero cell means black background; selected KALEIDO glyphs
// begin at code 65, so zero never conflicts with a visible pattern cell.
EXT_RAM_BSS_ATTR static uint8_t
stage_eight_cells[DEMO_STAGE_EIGHT_COLUMNS * DEMO_STAGE_EIGHT_ROWS];
EXT_RAM_BSS_ATTR static uint8_t stage_eight_glyphs[DEMO_STAGE_EIGHT_GLYPH_COUNT];
static uint8_t stage_eight_next_radius;
static uint32_t stage_eight_next_ring_at;
static uint32_t stage_eight_hold_until;
static bool stage_eight_holding;
static void setStageEightCell(int column, int row, uint8_t glyph)
{
if (column < 0 || column >= DEMO_STAGE_EIGHT_COLUMNS ||
row < 0 || row >= DEMO_STAGE_EIGHT_ROWS) return;
stage_eight_cells[(size_t)row * DEMO_STAGE_EIGHT_COLUMNS + (size_t)column] = glyph;
}
static void addStageEightRing(uint8_t radius)
{
// BASIC lines 210-280 choose one point in an octant, then write its eight
// reflected partners. R(0) marks the outer points; the remaining selected
// PET glyphs fill toward the axes, echoing the BASIC subroutine at line 900.
for (uint8_t offset = 0U; offset <= radius; ++offset) {
const uint8_t glyph = offset == radius ? stage_eight_glyphs[0U] :
stage_eight_glyphs[1U + (offset - 1U) % (DEMO_STAGE_EIGHT_GLYPH_COUNT - 1U)];
const int wide = (int)radius;
const int narrow = (int)offset;
const int centre_x = DEMO_STAGE_EIGHT_CENTRE_COLUMN;
const int centre_y = DEMO_STAGE_EIGHT_CENTRE_ROW;
setStageEightCell(centre_x + wide, centre_y + narrow, glyph);
setStageEightCell(centre_x + wide, centre_y - narrow, glyph);
setStageEightCell(centre_x - wide, centre_y + narrow, glyph);
setStageEightCell(centre_x - wide, centre_y - narrow, glyph);
setStageEightCell(centre_x + narrow, centre_y + wide, glyph);
setStageEightCell(centre_x + narrow, centre_y - wide, glyph);
setStageEightCell(centre_x - narrow, centre_y + wide, glyph);
setStageEightCell(centre_x - narrow, centre_y - wide, glyph);
}
}
static void beginStageEightPattern(uint32_t now_ms)
{
memset(stage_eight_cells, 0, sizeof(stage_eight_cells));
for (size_t glyph = 0U; glyph < DEMO_STAGE_EIGHT_GLYPH_COUNT; ++glyph) {
uint8_t character = DEMO_STAGE_EIGHT_GRAPHIC_FIRST +
(uint8_t)(esp_random() % DEMO_STAGE_EIGHT_GRAPHIC_COUNT);
// A high bit selects PET reverse video: black figure on a white cell.
if (esp_random() % 100U < DEMO_STAGE_EIGHT_REVERSE_PERCENT) character |= 0x80U;
stage_eight_glyphs[glyph] = character;
}
stage_eight_next_radius = 1U;
stage_eight_holding = false;
addStageEightRing(stage_eight_next_radius++);
stage_eight_next_ring_at = now_ms + DEMO_STAGE_EIGHT_RING_MS;
}
void demoStageKaleidoStart(uint32_t now_ms)
{
beginStageEightPattern(now_ms);
}
void demoStageKaleidoUpdate(uint32_t now_ms)
{
if (stage_eight_holding) {
if ((int32_t)(now_ms - stage_eight_hold_until) >= 0) beginStageEightPattern(now_ms);
return;
}
if ((int32_t)(now_ms - stage_eight_next_ring_at) < 0) return;
addStageEightRing(stage_eight_next_radius++);
stage_eight_next_ring_at += DEMO_STAGE_EIGHT_RING_MS;
if (stage_eight_next_radius > DEMO_STAGE_EIGHT_MAX_RADIUS) {
stage_eight_holding = true;
stage_eight_hold_until = now_ms + DEMO_STAGE_EIGHT_HOLD_MS;
}
}
void demoStageKaleidoDraw(uint16_t *frame)
{
// The working cells already contain normal or reverse PET display codes.
// Draw only nonzero cells over Demo's black-cleared background. Rows 19
// and 20 stay clear for the normal scale-two bottom ticker.
for (int row = 0; row < DEMO_STAGE_EIGHT_ROWS; ++row) {
for (int column = 0; column < DEMO_STAGE_EIGHT_COLUMNS; ++column) {
const uint8_t glyph = stage_eight_cells[(size_t)row *
DEMO_STAGE_EIGHT_COLUMNS +
(size_t)column];
if (glyph == 0U) continue;
drawPet2001Char(frame, column * (int)PET2001_FONT_GLYPH_WIDTH,
row * (int)PET2001_FONT_GLYPH_HEIGHT, glyph,
DEMO_STAGE_EIGHT_FOREGROUND, COLOR_BLACK, 1);
}
}
}