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)
  1. Decisioncolumn < 0 || column >= DEMO_STAGE_EIGHT_COLUMNS || row < 0 || row >= DEMO_STAGE_EIGHT_ROWS
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  2. Executestage_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:

  1. FOR loopuint8_t offset = 0U; offset <= radius; ++offset

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst uint8_t glyph = offset == radius ? stage_eight_glyphs[0U] : stage_eight_glyphs[1U + (offset - 1U) % (DEMO_STAGE_EIGHT_GLYPH_COUNT - 1U)];
      2. Executeconst int wide = (int)radius;
      3. Executeconst int narrow = (int)offset;
      4. Executeconst int centre_x = DEMO_STAGE_EIGHT_CENTRE_COLUMN;
      5. Executeconst int centre_y = DEMO_STAGE_EIGHT_CENTRE_ROW;
      6. ExecutesetStageEightCell(centre_x + wide, centre_y + narrow, glyph);
      7. ExecutesetStageEightCell(centre_x + wide, centre_y - narrow, glyph);
      8. ExecutesetStageEightCell(centre_x - wide, centre_y + narrow, glyph);
      9. ExecutesetStageEightCell(centre_x - wide, centre_y - narrow, glyph);
      10. ExecutesetStageEightCell(centre_x + narrow, centre_y + wide, glyph);
      11. ExecutesetStageEightCell(centre_x + narrow, centre_y - wide, glyph);
      12. ExecutesetStageEightCell(centre_x - narrow, centre_y + wide, glyph);
      13. ExecutesetStageEightCell(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:

  1. Executememset(stage_eight_cells, 0, sizeof(stage_eight_cells));
  2. FOR loopsize_t glyph = 0U; glyph < DEMO_STAGE_EIGHT_GLYPH_COUNT; ++glyph

    Repeat body while the loop condition permits; then continue below.

      1. Executeuint8_t character = DEMO_STAGE_EIGHT_GRAPHIC_FIRST + (uint8_t)(esp_random() % DEMO_STAGE_EIGHT_GRAPHIC_COUNT);
      2. Decisionesp_random() % 100U < DEMO_STAGE_EIGHT_REVERSE_PERCENT
        True
        1. Executecharacter |= 0x80U;
        False

        Continue after this decision.

      3. Executestage_eight_glyphs[glyph] = character;
  3. Executestage_eight_next_radius = 1U;
  4. Executestage_eight_holding = false;
  5. ExecuteaddStageEightRing(stage_eight_next_radius++);
  6. Executestage_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:

  1. ExecutebeginStageEightPattern(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:

  1. Decisionstage_eight_holding
    True
      1. Decision(int32_t)(now_ms - stage_eight_hold_until) >= 0
        True
        1. ExecutebeginStageEightPattern(now_ms);
        False

        Continue after this decision.

      2. Exit this functionreturn;
    False

    Continue after this decision.

  2. Decision(int32_t)(now_ms - stage_eight_next_ring_at) < 0
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  3. ExecuteaddStageEightRing(stage_eight_next_radius++);
  4. Executestage_eight_next_ring_at += DEMO_STAGE_EIGHT_RING_MS;
  5. Decisionstage_eight_next_radius > DEMO_STAGE_EIGHT_MAX_RADIUS
    True
      1. Executestage_eight_holding = true;
      2. Executestage_eight_hold_until = now_ms + DEMO_STAGE_EIGHT_HOLD_MS;
    False

    Continue 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:

  1. FOR loopint row = 0; row < DEMO_STAGE_EIGHT_ROWS; ++row

    Repeat body while the loop condition permits; then continue below.

      1. FOR loopint column = 0; column < DEMO_STAGE_EIGHT_COLUMNS; ++column

        Repeat body while the loop condition permits; then continue below.

          1. Executeconst uint8_t glyph = stage_eight_cells[(size_t)row * DEMO_STAGE_EIGHT_COLUMNS + (size_t)column];
          2. Decisionglyph == 0U
            True
            1. Next loop iterationcontinue;
            False

            Continue after this decision.

          3. ExecutedrawPet2001Char(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);
        }
    }
}