Squares
Source: src/demo_stage_squares.c · 160 lines · 7 functions.
Squares screen captures
Four moments from the running Squares demo. The PET characters build expanding nested outlines one cell at a time, with a new glyph and reverse-video choice for each square.




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
setStageTenCell() · source line 50
static void setStageTenCell(int column, int row, uint8_t glyph)
- Decision
column < 0 || column >= DEMO_STAGE_TEN_COLUMNS || row < 0 || row >= DEMO_STAGE_TEN_ROWSTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
stage_ten_cells[(size_t)row * DEMO_STAGE_TEN_COLUMNS + (size_t)column] = glyph;
Read original function source
static void setStageTenCell(int column, int row, uint8_t glyph)
{
if (column < 0 || column >= DEMO_STAGE_TEN_COLUMNS ||
row < 0 || row >= DEMO_STAGE_TEN_ROWS) return;
stage_ten_cells[(size_t)row * DEMO_STAGE_TEN_COLUMNS + (size_t)column] = glyph;
}beginStageTenSquare() · source line 57
static void beginStageTenSquare(uint32_t now_ms)
- Execute
stage_ten_glyph = 65U + (uint8_t)(esp_random() % 63U); - Decision
(esp_random() & 1U) != 0UTrue- Execute
stage_ten_glyph |= 0x80U;
FalseContinue after this decision.
- Execute
stage_ten_edge_step = 0U; - Execute
stage_ten_phase = SQUARES_DRAW_BOTTOM; - Execute
stage_ten_next_update_at = now_ms;
Read original function source
static void beginStageTenSquare(uint32_t now_ms)
{
// BASIC line 140 chooses a new display character and line 160 sometimes
// enables reverse video. The high bit carries that reverse-video choice in
// the existing PET renderer, as it does for KALEIDO.
stage_ten_glyph = 65U + (uint8_t)(esp_random() % 63U);
if ((esp_random() & 1U) != 0U) stage_ten_glyph |= 0x80U;
stage_ten_edge_step = 0U;
stage_ten_phase = SQUARES_DRAW_BOTTOM;
stage_ten_next_update_at = now_ms;
}demoStageSquaresStart() · source line 69
void demoStageSquaresStart(uint32_t now_ms)
Calls into this documentation:
- Execute
memset(stage_ten_cells, 0, sizeof(stage_ten_cells)); - Execute
stage_ten_draw_step_ms = DEMO_STAGE_TEN_DRAW_STEP_MIN_MS + (esp_random() % DEMO_STAGE_TEN_DRAW_STEP_RANGE_MS); - Execute
stage_ten_size = 1U; - Execute
beginStageTenSquare(now_ms);
Read original function source
void demoStageSquaresStart(uint32_t now_ms)
{
memset(stage_ten_cells, 0, sizeof(stage_ten_cells));
stage_ten_draw_step_ms = DEMO_STAGE_TEN_DRAW_STEP_MIN_MS +
(esp_random() % DEMO_STAGE_TEN_DRAW_STEP_RANGE_MS);
stage_ten_size = 1U;
beginStageTenSquare(now_ms);
}drawNextStageTenSquareCell() · source line 78
static void drawNextStageTenSquareCell(void)
Calls into this documentation:
- Execute
const int right = DEMO_STAGE_TEN_ANCHOR_COLUMN; - Execute
const int bottom = DEMO_STAGE_TEN_ANCHOR_ROW; - Execute
const int left = right - (int)stage_ten_size + 1; - Execute
const int top = bottom - (int)stage_ten_size + 1; - Execute
const int step = (int)stage_ten_edge_step; - Select a case
stage_ten_phaseEnter matching case; follow source fall-through until a break, return or end.
- Case / label
case SQUARES_DRAW_BOTTOM: - Execute
setStageTenCell(left + step, bottom, stage_ten_glyph); - Exit enclosing loop or switch
break; - Case / label
case SQUARES_DRAW_RIGHT: - Execute
setStageTenCell(right, bottom - step, stage_ten_glyph); - Exit enclosing loop or switch
break; - Case / label
case SQUARES_DRAW_TOP: - Execute
setStageTenCell(right - step, top, stage_ten_glyph); - Exit enclosing loop or switch
break; - Case / label
case SQUARES_DRAW_LEFT: - Execute
setStageTenCell(left, top + step, stage_ten_glyph); - Exit enclosing loop or switch
break; - Case / label
case SQUARES_HOLD: - Exit enclosing loop or switch
break;
Read original function source
static void drawNextStageTenSquareCell(void)
{
// This is the PET cursor choreography behind BASIC lines 170-220. The
// original writes a character along the bottom, then travels up, left, and
// down again to return to its anchor. Direct cell coordinates retain the
// same expanding-square result without relying on terminal cursor wrapping.
const int right = DEMO_STAGE_TEN_ANCHOR_COLUMN;
const int bottom = DEMO_STAGE_TEN_ANCHOR_ROW;
const int left = right - (int)stage_ten_size + 1;
const int top = bottom - (int)stage_ten_size + 1;
const int step = (int)stage_ten_edge_step;
switch (stage_ten_phase) {
case SQUARES_DRAW_BOTTOM:
setStageTenCell(left + step, bottom, stage_ten_glyph);
break;
case SQUARES_DRAW_RIGHT:
setStageTenCell(right, bottom - step, stage_ten_glyph);
break;
case SQUARES_DRAW_TOP:
setStageTenCell(right - step, top, stage_ten_glyph);
break;
case SQUARES_DRAW_LEFT:
setStageTenCell(left, top + step, stage_ten_glyph);
break;
case SQUARES_HOLD:
break;
}
}advanceStageTenSquarePath() · source line 108
static void advanceStageTenSquarePath(uint32_t now_ms)
Calls into this documentation:
- Execute
++stage_ten_edge_step; - Decision
stage_ten_edge_step < stage_ten_sizeTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
stage_ten_edge_step = 0U; - Select a case
stage_ten_phaseEnter matching case; follow source fall-through until a break, return or end.
- Case / label
case SQUARES_DRAW_BOTTOM: - Execute
stage_ten_phase = SQUARES_DRAW_RIGHT; - Exit enclosing loop or switch
break; - Case / label
case SQUARES_DRAW_RIGHT: - Execute
stage_ten_phase = SQUARES_DRAW_TOP; - Exit enclosing loop or switch
break; - Case / label
case SQUARES_DRAW_TOP: - Execute
stage_ten_phase = SQUARES_DRAW_LEFT; - Exit enclosing loop or switch
break; - Case / label
case SQUARES_DRAW_LEFT: - Execute
++stage_ten_size; - Decision
stage_ten_size > DEMO_STAGE_TEN_MAX_SIZETrue- Execute
stage_ten_phase = SQUARES_HOLD; - Execute
stage_ten_hold_until = now_ms + DEMO_STAGE_TEN_HOLD_MS; - Execute
stage_ten_next_update_at = stage_ten_hold_until;
False- Execute
beginStageTenSquare(now_ms);
- Exit enclosing loop or switch
break; - Case / label
case SQUARES_HOLD: - Exit enclosing loop or switch
break;
Read original function source
static void advanceStageTenSquarePath(uint32_t now_ms)
{
++stage_ten_edge_step;
if (stage_ten_edge_step < stage_ten_size) return;
stage_ten_edge_step = 0U;
switch (stage_ten_phase) {
case SQUARES_DRAW_BOTTOM: stage_ten_phase = SQUARES_DRAW_RIGHT; break;
case SQUARES_DRAW_RIGHT: stage_ten_phase = SQUARES_DRAW_TOP; break;
case SQUARES_DRAW_TOP: stage_ten_phase = SQUARES_DRAW_LEFT; break;
case SQUARES_DRAW_LEFT:
++stage_ten_size;
if (stage_ten_size > DEMO_STAGE_TEN_MAX_SIZE) {
stage_ten_phase = SQUARES_HOLD;
stage_ten_hold_until = now_ms + DEMO_STAGE_TEN_HOLD_MS;
stage_ten_next_update_at = stage_ten_hold_until;
} else {
beginStageTenSquare(now_ms);
}
break;
case SQUARES_HOLD: break;
}
}demoStageSquaresUpdate() · source line 132
void demoStageSquaresUpdate(uint32_t now_ms)
Calls into this documentation:
- Decision
(int32_t)(now_ms - stage_ten_next_update_at) < 0True- Exit this function
return;
FalseContinue after this decision.
- Decision
stage_ten_phase == SQUARES_HOLDTrue- Execute
demoStageSquaresStart(now_ms); - Exit this function
return;
FalseContinue after this decision.
- Execute
drawNextStageTenSquareCell(); - Execute
stage_ten_next_update_at += stage_ten_draw_step_ms; - Execute
advanceStageTenSquarePath(now_ms);
Read original function source
void demoStageSquaresUpdate(uint32_t now_ms)
{
if ((int32_t)(now_ms - stage_ten_next_update_at) < 0) return;
if (stage_ten_phase == SQUARES_HOLD) {
demoStageSquaresStart(now_ms);
return;
}
drawNextStageTenSquareCell();
stage_ten_next_update_at += stage_ten_draw_step_ms;
advanceStageTenSquarePath(now_ms);
}demoStageSquaresDraw() · source line 145
void demoStageSquaresDraw(uint16_t *frame)
Calls into this documentation:
- FOR loop
int row = 0; row < DEMO_STAGE_TEN_ROWS; ++rowRepeat body while the loop condition permits; then continue below.
- FOR loop
int column = 0; column < DEMO_STAGE_TEN_COLUMNS; ++columnRepeat body while the loop condition permits; then continue below.
- Execute
const uint8_t glyph = stage_ten_cells[(size_t)row * DEMO_STAGE_TEN_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_TEN_FOREGROUND, COLOR_BLACK, 1);
Read original function source
void demoStageSquaresDraw(uint16_t *frame)
{
// SQUARES is another PET 40 x 19 cell scene. The normal scale-two ticker
// is drawn later and therefore remains entirely below this character map.
for (int row = 0; row < DEMO_STAGE_TEN_ROWS; ++row) {
for (int column = 0; column < DEMO_STAGE_TEN_COLUMNS; ++column) {
const uint8_t glyph = stage_ten_cells[(size_t)row *
DEMO_STAGE_TEN_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_TEN_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_squares.h"
#include "PET2001_font.h"
#include "c64_colors.h"
#include "esp_attr.h"
#include "esp_random.h"
#include "game_graphics.h"
#include <stddef.h>
#include <string.h>
// Segment 10 -- SQUARES, porting the PET cursor routine as expanding, nested outlines.
// The original 40 x 25 display could grow squares to 21 cells. The ticker leaves
// this port 19 rows high, so the fixed lower-right anchor and limit below keep
// every complete outline visible above it. Raise/lower both anchor coordinates
// with MAX_SIZE if you want to move or resize the whole nested-square field.
#define DEMO_STAGE_TEN_COLUMNS 40
#define DEMO_STAGE_TEN_ROWS 19
#define DEMO_STAGE_TEN_ANCHOR_COLUMN 28
#define DEMO_STAGE_TEN_ANCHOR_ROW 17
#define DEMO_STAGE_TEN_MAX_SIZE 17U
// BASIC line 130 picks one random delay for a whole set of nested squares.
// These bounds retain that variable speed; set RANGE to 1U for a fixed speed.
// Lower values draw faster.
#define DEMO_STAGE_TEN_DRAW_STEP_MIN_MS 6U
#define DEMO_STAGE_TEN_DRAW_STEP_RANGE_MS 20U
#define DEMO_STAGE_TEN_HOLD_MS 2600U
#define DEMO_STAGE_TEN_FOREGROUND COLOR_WHITE
typedef enum {
SQUARES_DRAW_BOTTOM,
SQUARES_DRAW_RIGHT,
SQUARES_DRAW_TOP,
SQUARES_DRAW_LEFT,
SQUARES_HOLD,
} squares_phase_t;
// SQUARES stores its completed character cells in PSRAM. The small cursor-like
// state below advances one printed PET character at a time around each edge.
EXT_RAM_BSS_ATTR static uint8_t
stage_ten_cells[DEMO_STAGE_TEN_COLUMNS * DEMO_STAGE_TEN_ROWS];
static squares_phase_t stage_ten_phase;
static uint8_t stage_ten_size;
static uint8_t stage_ten_edge_step;
static uint8_t stage_ten_glyph;
static uint32_t stage_ten_next_update_at;
static uint32_t stage_ten_hold_until;
static uint32_t stage_ten_draw_step_ms;
static void setStageTenCell(int column, int row, uint8_t glyph)
{
if (column < 0 || column >= DEMO_STAGE_TEN_COLUMNS ||
row < 0 || row >= DEMO_STAGE_TEN_ROWS) return;
stage_ten_cells[(size_t)row * DEMO_STAGE_TEN_COLUMNS + (size_t)column] = glyph;
}
static void beginStageTenSquare(uint32_t now_ms)
{
// BASIC line 140 chooses a new display character and line 160 sometimes
// enables reverse video. The high bit carries that reverse-video choice in
// the existing PET renderer, as it does for KALEIDO.
stage_ten_glyph = 65U + (uint8_t)(esp_random() % 63U);
if ((esp_random() & 1U) != 0U) stage_ten_glyph |= 0x80U;
stage_ten_edge_step = 0U;
stage_ten_phase = SQUARES_DRAW_BOTTOM;
stage_ten_next_update_at = now_ms;
}
void demoStageSquaresStart(uint32_t now_ms)
{
memset(stage_ten_cells, 0, sizeof(stage_ten_cells));
stage_ten_draw_step_ms = DEMO_STAGE_TEN_DRAW_STEP_MIN_MS +
(esp_random() % DEMO_STAGE_TEN_DRAW_STEP_RANGE_MS);
stage_ten_size = 1U;
beginStageTenSquare(now_ms);
}
static void drawNextStageTenSquareCell(void)
{
// This is the PET cursor choreography behind BASIC lines 170-220. The
// original writes a character along the bottom, then travels up, left, and
// down again to return to its anchor. Direct cell coordinates retain the
// same expanding-square result without relying on terminal cursor wrapping.
const int right = DEMO_STAGE_TEN_ANCHOR_COLUMN;
const int bottom = DEMO_STAGE_TEN_ANCHOR_ROW;
const int left = right - (int)stage_ten_size + 1;
const int top = bottom - (int)stage_ten_size + 1;
const int step = (int)stage_ten_edge_step;
switch (stage_ten_phase) {
case SQUARES_DRAW_BOTTOM:
setStageTenCell(left + step, bottom, stage_ten_glyph);
break;
case SQUARES_DRAW_RIGHT:
setStageTenCell(right, bottom - step, stage_ten_glyph);
break;
case SQUARES_DRAW_TOP:
setStageTenCell(right - step, top, stage_ten_glyph);
break;
case SQUARES_DRAW_LEFT:
setStageTenCell(left, top + step, stage_ten_glyph);
break;
case SQUARES_HOLD:
break;
}
}
static void advanceStageTenSquarePath(uint32_t now_ms)
{
++stage_ten_edge_step;
if (stage_ten_edge_step < stage_ten_size) return;
stage_ten_edge_step = 0U;
switch (stage_ten_phase) {
case SQUARES_DRAW_BOTTOM: stage_ten_phase = SQUARES_DRAW_RIGHT; break;
case SQUARES_DRAW_RIGHT: stage_ten_phase = SQUARES_DRAW_TOP; break;
case SQUARES_DRAW_TOP: stage_ten_phase = SQUARES_DRAW_LEFT; break;
case SQUARES_DRAW_LEFT:
++stage_ten_size;
if (stage_ten_size > DEMO_STAGE_TEN_MAX_SIZE) {
stage_ten_phase = SQUARES_HOLD;
stage_ten_hold_until = now_ms + DEMO_STAGE_TEN_HOLD_MS;
stage_ten_next_update_at = stage_ten_hold_until;
} else {
beginStageTenSquare(now_ms);
}
break;
case SQUARES_HOLD: break;
}
}
void demoStageSquaresUpdate(uint32_t now_ms)
{
if ((int32_t)(now_ms - stage_ten_next_update_at) < 0) return;
if (stage_ten_phase == SQUARES_HOLD) {
demoStageSquaresStart(now_ms);
return;
}
drawNextStageTenSquareCell();
stage_ten_next_update_at += stage_ten_draw_step_ms;
advanceStageTenSquarePath(now_ms);
}
void demoStageSquaresDraw(uint16_t *frame)
{
// SQUARES is another PET 40 x 19 cell scene. The normal scale-two ticker
// is drawn later and therefore remains entirely below this character map.
for (int row = 0; row < DEMO_STAGE_TEN_ROWS; ++row) {
for (int column = 0; column < DEMO_STAGE_TEN_COLUMNS; ++column) {
const uint8_t glyph = stage_ten_cells[(size_t)row *
DEMO_STAGE_TEN_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_TEN_FOREGROUND, COLOR_BLACK, 1);
}
}
}