About
Source: src/about.c · 235 lines · 10 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
select_message() · source line 42
static void select_message(void)
- Execute
uint8_t next = esp_random() % MESSAGE_COUNT; - Decision
last_message < MESSAGE_COUNTTrue- Execute
next = esp_random() % (MESSAGE_COUNT - 1U); - Decision
next >= last_messageTrue- Execute
++next;
FalseContinue after this decision.
FalseContinue after this decision.
- Execute
message_index = next; - Execute
last_message = next;
Read original function source
static void select_message(void)
{
uint8_t next = esp_random() % MESSAGE_COUNT;
if (last_message < MESSAGE_COUNT) {
next = esp_random() % (MESSAGE_COUNT - 1U);
if (next >= last_message) ++next;
}
message_index = next;
last_message = next;
}draw_about_text() · source line 53
static void draw_about_text(uint16_t *frame, const char *text, int y, int scale,
int x_offset, uint16_t color, unsigned visible)Calls into this documentation:
- Execute
char clipped[32]; - Execute
unsigned length = 0; - WHILE loop
text[length] != '\0' && length + 1U < sizeof(clipped)Repeat body while the loop condition permits; then continue below.
- Execute
++length;
- Decision
visible < lengthTrue- Execute
length = visible;
FalseContinue after this decision.
- FOR loop
unsigned i = 0; i < length; ++iRepeat body while the loop condition permits; then continue below.
- Execute
clipped[i] = text[i];
- Execute
clipped[length] = '\0'; - Execute
draw_text_centred(frame, 160 + x_offset + 2, y + 2, clipped, scale, COLOR_DARKRED); - Execute
draw_text_centred(frame, 160 + x_offset, y, clipped, scale, color);
Read original function source
static void draw_about_text(uint16_t *frame, const char *text, int y, int scale,
int x_offset, uint16_t color, unsigned visible)
{
char clipped[32];
unsigned length = 0;
while (text[length] != '\0' && length + 1U < sizeof(clipped)) ++length;
if (visible < length) length = visible;
for (unsigned i = 0; i < length; ++i) clipped[i] = text[i];
clipped[length] = '\0';
draw_text_centred(frame, 160 + x_offset + 2, y + 2, clipped, scale, COLOR_DARKRED);
draw_text_centred(frame, 160 + x_offset, y, clipped, scale, color);
}draw_wave_text() · source line 66
static void draw_wave_text(uint16_t *frame, const char *text, int y, int scale,
uint16_t color, uint32_t elapsed)Calls into this documentation:
- Execute
unsigned length = 0; - WHILE loop
text[length] != '\0'Repeat body while the loop condition permits; then continue below.
- Execute
++length;
- Execute
int x = 160 - ((int)length * UI_FONT_ADVANCE * scale - scale) / 2; - Execute
const float base_phase = ((float)(elapsed % WAVE_CYCLE_MS) / WAVE_CYCLE_MS) * 6.2831853f; - FOR loop
unsigned index = 0; index < length; ++indexRepeat body while the loop condition permits; then continue below.
- Execute
const char character[2] = {text[index], '\0'}; - Execute
const int wave_y = y + (int)(sinf(base_phase + (float)index * 0.55f) * WAVE_HEIGHT); - Execute
draw_text(frame, x + 2, wave_y + 2, character, scale, COLOR_DARKRED); - Execute
draw_text(frame, x, wave_y, character, scale, color); - Execute
x += UI_FONT_ADVANCE * scale;
Read original function source
static void draw_wave_text(uint16_t *frame, const char *text, int y, int scale,
uint16_t color, uint32_t elapsed)
{
unsigned length = 0;
while (text[length] != '\0') ++length;
int x = 160 - ((int)length * UI_FONT_ADVANCE * scale - scale) / 2;
const float base_phase =
((float)(elapsed % WAVE_CYCLE_MS) / WAVE_CYCLE_MS) * 6.2831853f;
for (unsigned index = 0; index < length; ++index) {
const char character[2] = {text[index], '\0'};
const int wave_y = y +
(int)(sinf(base_phase + (float)index * 0.55f) * WAVE_HEIGHT);
draw_text(frame, x + 2, wave_y + 2, character, scale, COLOR_DARKRED);
draw_text(frame, x, wave_y, character, scale, color);
x += UI_FONT_ADVANCE * scale;
}
}draw_transformed_text() · source line 86
static void draw_transformed_text(uint16_t *frame, const char *text, int y,
int scale, float zoom, float angle,
uint16_t color)Calls into this documentation:
- Execute
draw_text_transformed(frame, 162, y + (UI_FONT_HEIGHT * scale) / 2 + 2, text, scale, zoom, angle, COLOR_DARKRED); - Execute
draw_text_transformed(frame, 160, y + (UI_FONT_HEIGHT * scale) / 2, text, scale, zoom, angle, color);
Read original function source
static void draw_transformed_text(uint16_t *frame, const char *text, int y,
int scale, float zoom, float angle,
uint16_t color)
{
draw_text_transformed(frame, 162, y + (UI_FONT_HEIGHT * scale) / 2 + 2, text,
scale, zoom, angle, COLOR_DARKRED);
draw_text_transformed(frame, 160, y + (UI_FONT_HEIGHT * scale) / 2, text,
scale, zoom, angle, color);
}draw_animated_text() · source line 96
static void draw_animated_text(uint16_t *frame, uint32_t elapsed)
Calls into this documentation:
- Execute
const char *subtitle = messages[message_index]; - Execute
const unsigned title_length = 9U; - Execute
unsigned subtitle_length = 0; - WHILE loop
subtitle[subtitle_length] != '\0'Repeat body while the loop condition permits; then continue below.
- Execute
++subtitle_length;
- Execute
draw_text_centred(frame, 160, 7, "CODED BY", 1, COLOR_LIGHTGRAY); - Execute
const uint8_t title_effect = effect_preset / 11U; - Execute
const uint8_t subtitle_effect = effect_preset % 11U; - Execute
int title_x = 0; - Execute
int subtitle_x = 0; - Execute
int title_y = 20; - Execute
int subtitle_y = 57; - Execute
unsigned title_visible = title_length; - Execute
unsigned subtitle_visible = subtitle_length; - Execute
uint16_t title_color = COLOR_YELLOW; - Execute
uint16_t subtitle_color = COLOR_ORANGE; - Execute
float title_angle = 0.0f, subtitle_angle = 0.0f; - Execute
float title_zoom = 1.0f, subtitle_zoom = 1.0f; - Execute
bool title_wave = false, subtitle_wave = false; - Select a case
title_effectEnter matching case; follow source fall-through until a break, return or end.
- Case / label
case 0: - Execute
title_x = 200 - (int)((elapsed * 55U / 1000U) % 400U); - Exit enclosing loop or switch
break; - Case / label
case 1: - Execute
title_x = (int)((elapsed * 55U / 1000U) % 100U) - 50; - Exit enclosing loop or switch
break; - Case / label
case 2: - Execute
title_y += (int)(sinf((float)elapsed / 445.0f) * 18.0f); - Exit enclosing loop or switch
break; - Case / label
case 3: - Execute
title_wave = true; - Exit enclosing loop or switch
break; - Case / label
case 4: - Execute
title_x = (int)((elapsed / 18U) % 7U) - 3; - Exit enclosing loop or switch
break; - Case / label
case 5: - Execute
title_visible = (elapsed / 130U) % (title_length + 1U); - Exit enclosing loop or switch
break; - Case / label
case 6: - Execute
title_color = (uint16_t[]){COLOR_DARKRED, COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_WHITE}[(elapsed / 180U) % 5U]; - Exit enclosing loop or switch
break; - Case / label
case 7: - Execute
title_angle = sinf((float)elapsed / 382.0f) * 12.0f; - Exit enclosing loop or switch
break; - Case / label
case 8: - Execute
title_zoom = 0.88f + (sinf((float)elapsed / 318.0f) + 1.0f) * 0.10f; - Exit enclosing loop or switch
break; - Case / label
case 9: - Execute
title_y += (int)(18.0f - fminf(18.0f, (float)(elapsed % 2800U) * 18.0f / 700.0f)); - Exit enclosing loop or switch
break; - Case / label
case 10: - Execute
title_visible = (elapsed / 90U) % (title_length + 1U); - Exit enclosing loop or switch
break; - Case / label
default: - Exit enclosing loop or switch
break;
- Select a case
subtitle_effectEnter matching case; follow source fall-through until a break, return or end.
- Case / label
case 0: - Execute
subtitle_x = 220 - (int)((elapsed * 45U / 1000U) % 440U); - Exit enclosing loop or switch
break; - Case / label
case 1: - Execute
subtitle_x = (int)((elapsed * 55U / 1000U) % 100U) - 50; - Exit enclosing loop or switch
break; - Case / label
case 2: - Execute
subtitle_y += (int)(sinf((float)elapsed / 445.0f) * 30.0f); - Exit enclosing loop or switch
break; - Case / label
case 3: - Execute
subtitle_wave = true; - Exit enclosing loop or switch
break; - Case / label
case 4: - Execute
subtitle_x = (int)((elapsed / 16U) % 7U) - 3; - Exit enclosing loop or switch
break; - Case / label
case 5: - Execute
subtitle_visible = (elapsed / 130U) % (subtitle_length + 1U); - Exit enclosing loop or switch
break; - Case / label
case 6: - Execute
subtitle_color = (uint16_t[]){COLOR_DARKRED, COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_WHITE}[(elapsed / 180U) % 5U]; - Exit enclosing loop or switch
break; - Case / label
case 7: - Execute
subtitle_angle = sinf((float)elapsed / 382.0f) * 12.0f; - Exit enclosing loop or switch
break; - Case / label
case 8: - Execute
subtitle_zoom = 0.88f + (sinf((float)elapsed / 318.0f) + 1.0f) * 0.10f; - Exit enclosing loop or switch
break; - Case / label
case 9: - Execute
subtitle_y += (int)(18.0f - fminf(18.0f, (float)(elapsed % 2800U) * 18.0f / 700.0f)); - Exit enclosing loop or switch
break; - Case / label
case 10: - Execute
subtitle_visible = (elapsed / 90U) % (subtitle_length + 1U); - Exit enclosing loop or switch
break; - Case / label
default: - Exit enclosing loop or switch
break;
- Decision
title_waveTrue- Execute
draw_wave_text(frame, "JD and MI", title_y, 3, title_color, elapsed);
False- Decision
title_angle != 0.0f || title_zoom != 1.0fTrue- Execute
draw_transformed_text(frame, "JD and MI", title_y, 3, title_zoom, title_angle, title_color);
False- Execute
draw_about_text(frame, "JD and MI", title_y, 3, title_x, title_color, title_visible);
- Decision
subtitle_waveTrue- Execute
draw_wave_text(frame, subtitle, subtitle_y, 1, subtitle_color, elapsed);
False- Decision
subtitle_angle != 0.0f || subtitle_zoom != 1.0fTrue- Execute
draw_transformed_text(frame, subtitle, subtitle_y, 1, subtitle_zoom, subtitle_angle, subtitle_color);
False- Execute
draw_about_text(frame, subtitle, subtitle_y, 1, subtitle_x, subtitle_color, subtitle_visible);
Read original function source
static void draw_animated_text(uint16_t *frame, uint32_t elapsed)
{
const char *subtitle = messages[message_index];
const unsigned title_length = 9U;
unsigned subtitle_length = 0;
while (subtitle[subtitle_length] != '\0') ++subtitle_length;
draw_text_centred(frame, 160, 7, "CODED BY", 1, COLOR_LIGHTGRAY);
const uint8_t title_effect = effect_preset / 11U;
const uint8_t subtitle_effect = effect_preset % 11U;
int title_x = 0;
int subtitle_x = 0;
int title_y = 20;
int subtitle_y = 57;
unsigned title_visible = title_length;
unsigned subtitle_visible = subtitle_length;
uint16_t title_color = COLOR_YELLOW;
uint16_t subtitle_color = COLOR_ORANGE;
float title_angle = 0.0f, subtitle_angle = 0.0f;
float title_zoom = 1.0f, subtitle_zoom = 1.0f;
bool title_wave = false, subtitle_wave = false;
switch (title_effect) {
case 0: title_x = 200 - (int)((elapsed * 55U / 1000U) % 400U); break;
case 1: title_x = (int)((elapsed * 55U / 1000U) % 100U) - 50; break;
case 2: title_y += (int)(sinf((float)elapsed / 445.0f) * 18.0f); break;
case 3: title_wave = true; break;
case 4: title_x = (int)((elapsed / 18U) % 7U) - 3; break;
case 5: title_visible = (elapsed / 130U) % (title_length + 1U); break;
case 6: title_color = (uint16_t[]){COLOR_DARKRED, COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_WHITE}[(elapsed / 180U) % 5U]; break;
case 7: title_angle = sinf((float)elapsed / 382.0f) * 12.0f; break;
case 8: title_zoom = 0.88f + (sinf((float)elapsed / 318.0f) + 1.0f) * 0.10f; break;
case 9: title_y += (int)(18.0f - fminf(18.0f, (float)(elapsed % 2800U) * 18.0f / 700.0f)); break;
case 10: title_visible = (elapsed / 90U) % (title_length + 1U); break;
default: break;
}
switch (subtitle_effect) {
case 0: subtitle_x = 220 - (int)((elapsed * 45U / 1000U) % 440U); break;
case 1: subtitle_x = (int)((elapsed * 55U / 1000U) % 100U) - 50; break;
case 2: subtitle_y += (int)(sinf((float)elapsed / 445.0f) * 30.0f); break;
case 3: subtitle_wave = true; break;
case 4: subtitle_x = (int)((elapsed / 16U) % 7U) - 3; break;
case 5: subtitle_visible = (elapsed / 130U) % (subtitle_length + 1U); break;
case 6: subtitle_color = (uint16_t[]){COLOR_DARKRED, COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_WHITE}[(elapsed / 180U) % 5U]; break;
case 7: subtitle_angle = sinf((float)elapsed / 382.0f) * 12.0f; break;
case 8: subtitle_zoom = 0.88f + (sinf((float)elapsed / 318.0f) + 1.0f) * 0.10f; break;
case 9: subtitle_y += (int)(18.0f - fminf(18.0f, (float)(elapsed % 2800U) * 18.0f / 700.0f)); break;
case 10: subtitle_visible = (elapsed / 90U) % (subtitle_length + 1U); break;
default: break;
}
if (title_wave) {
draw_wave_text(frame, "JD and MI", title_y, 3, title_color, elapsed);
} else if (title_angle != 0.0f || title_zoom != 1.0f) {
draw_transformed_text(frame, "JD and MI", title_y, 3, title_zoom,
title_angle, title_color);
} else {
draw_about_text(frame, "JD and MI", title_y, 3, title_x, title_color, title_visible);
}
if (subtitle_wave) {
draw_wave_text(frame, subtitle, subtitle_y, 1, subtitle_color, elapsed);
} else if (subtitle_angle != 0.0f || subtitle_zoom != 1.0f) {
draw_transformed_text(frame, subtitle, subtitle_y, 1, subtitle_zoom,
subtitle_angle, subtitle_color);
} else {
draw_about_text(frame, subtitle, subtitle_y, 1, subtitle_x, subtitle_color, subtitle_visible);
}
}startAbout() · source line 166
void startAbout(uint32_t now_ms)
Calls into this documentation:
- Execute
flameEffectInitialize(&fire, heat, FIRE_COLUMNS, FIRE_ROWS, FIRE_PIXEL_WIDTH, FIRE_PIXEL_HEIGHT, true, esp_random()); - Execute
select_message(); - Execute
effect_preset = esp_random() % EFFECT_PRESET_COUNT; - Execute
started_at = last_frame = now_ms; - Execute
startMoonlight(now_ms); - Execute
showing_credits = false; - Execute
running = true;
Read original function source
void startAbout(uint32_t now_ms)
{
flameEffectInitialize(&fire, heat, FIRE_COLUMNS, FIRE_ROWS, FIRE_PIXEL_WIDTH,
FIRE_PIXEL_HEIGHT, true, esp_random());
select_message();
effect_preset = esp_random() % EFFECT_PRESET_COUNT;
started_at = last_frame = now_ms;
startMoonlight(now_ms);
showing_credits = false;
running = true;
}stopAbout() · source line 178
void stopAbout(void)
Calls into this documentation:
- Execute
stopCredits(); - Execute
stopMoonlight(); - Execute
showing_credits = false; - Execute
running = false;
Read original function source
void stopAbout(void)
{
stopCredits();
stopMoonlight();
showing_credits = false;
running = false;
}updateAbout() · source line 186
void updateAbout(uint32_t now_ms)
Calls into this documentation:
- Decision
!running || showing_credits || now_ms - last_frame < FRAME_MSTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
updateMoonlight(now_ms); - Execute
last_frame = now_ms; - Execute
flameEffectUpdate(&fire);
Read original function source
void updateAbout(uint32_t now_ms)
{
if (!running || showing_credits || now_ms - last_frame < FRAME_MS) return;
updateMoonlight(now_ms);
last_frame = now_ms;
flameEffectUpdate(&fire);
}aboutAction() · source line 194
void aboutAction(bool next, bool select, uint32_t now_ms)
Calls into this documentation:
- Decision
!runningTrue- Exit this function
return;
FalseContinue after this decision.
- Decision
showing_creditsTrue- Decision
creditsAction(next, select)True- Execute
showing_credits = false; - Execute
started_at = last_frame = now_ms; - Execute
select_message(); - Execute
startMoonlight(now_ms);
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
selectTrue- Execute
stopMoonlight(); - Execute
showing_credits = true; - Execute
startCredits(); - Exit this function
return;
FalseContinue after this decision.
- Decision
nextTrue- Execute
effect_preset = (effect_preset + 1U) % EFFECT_PRESET_COUNT; - Execute
started_at = last_frame = now_ms;
FalseContinue after this decision.
Read original function source
void aboutAction(bool next, bool select, uint32_t now_ms)
{
if (!running) return;
if (showing_credits) {
if (creditsAction(next, select)) {
showing_credits = false;
started_at = last_frame = now_ms;
select_message();
startMoonlight(now_ms);
}
return;
}
if (select) {
stopMoonlight();
showing_credits = true;
startCredits();
return;
}
if (next) {
effect_preset = (effect_preset + 1U) % EFFECT_PRESET_COUNT;
started_at = last_frame = now_ms;
}
}drawAbout() · source line 218
void drawAbout(uint16_t *frame)
Calls into this documentation:
- Decision
!runningTrue- Exit this function
return;
FalseContinue after this decision.
- Decision
showing_creditsTrue- Execute
drawCredits(frame); - Exit this function
return;
FalseContinue after this decision.
- Execute
clear(frame, COLOR_BLACK); - Execute
draw_animated_text(frame, last_frame - started_at); - Execute
flameEffectDraw(frame, &fire, 0, FIRE_TOP, NULL); - Execute
draw_text_centred(frame, 157, 158, "A NEXT BOOT EXIT", 2, COLOR_DARKGRAY); - Execute
draw_text_centred(frame, 158, 157, "A NEXT BOOT EXIT", 2, COLOR_LIGHTGRAY);
Read original function source
void drawAbout(uint16_t *frame)
{
if (!running) return;
if (showing_credits) {
drawCredits(frame);
return;
}
clear(frame, COLOR_BLACK);
draw_animated_text(frame, last_frame - started_at);
// NULL preserves About's original Doom-style orange flame palette.
flameEffectDraw(frame, &fire, 0, FIRE_TOP, NULL);
// A one-pixel offset gives the compact built-in font a readable bold edge.
draw_text_centred(frame, 157, 158, "A NEXT BOOT EXIT", 2, COLOR_DARKGRAY);
draw_text_centred(frame, 158, 157, "A NEXT BOOT EXIT", 2, COLOR_LIGHTGRAY);
}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "about.h"
#include "game_graphics.h"
#include "PET2001_font.h"
#include "credits.h"
#include "flame_effect.h"
#include "moonlight.h"
#include "esp_random.h"
#include <math.h>
#include <stddef.h>
#define FIRE_TOP (LCD_HEIGHT / 2)
#define FIRE_PIXEL_WIDTH 2
#define FIRE_PIXEL_HEIGHT 2
#define FIRE_COLUMNS (LCD_WIDTH / FIRE_PIXEL_WIDTH)
#define FIRE_ROWS ((LCD_HEIGHT - FIRE_TOP + FIRE_PIXEL_HEIGHT - 1) / FIRE_PIXEL_HEIGHT)
#define FIRE_CELL_COUNT (FIRE_COLUMNS * FIRE_ROWS)
#define FRAME_MS 20U
#define MESSAGE_COUNT 6U
#define EFFECT_PRESET_COUNT 121U
#define WAVE_CYCLE_MS 900U
#define WAVE_HEIGHT 5
static const char *const messages[MESSAGE_COUNT] = {
"FORGED IN FIRE - 2026",
"CODED IN HELL - 2026",
"TWO MINDS. ONE MACHINE.",
"BUILT TO SURVIVE - 2026",
"POWERED BY BAD IDEAS",
"IT COMPILED. SHIP IT.",
};
static uint8_t heat[FIRE_CELL_COUNT];
static flame_effect_t fire;
static uint8_t message_index;
static uint8_t last_message = MESSAGE_COUNT;
static uint8_t effect_preset;
static uint32_t started_at;
static uint32_t last_frame;
static bool running;
static bool showing_credits;
static void select_message(void)
{
uint8_t next = esp_random() % MESSAGE_COUNT;
if (last_message < MESSAGE_COUNT) {
next = esp_random() % (MESSAGE_COUNT - 1U);
if (next >= last_message) ++next;
}
message_index = next;
last_message = next;
}
static void draw_about_text(uint16_t *frame, const char *text, int y, int scale,
int x_offset, uint16_t color, unsigned visible)
{
char clipped[32];
unsigned length = 0;
while (text[length] != '\0' && length + 1U < sizeof(clipped)) ++length;
if (visible < length) length = visible;
for (unsigned i = 0; i < length; ++i) clipped[i] = text[i];
clipped[length] = '\0';
drawPet2001TextCentredTransparent(frame, 160 + x_offset + 2, y + 2, clipped,
COLOR_DARKRED, scale);
drawPet2001TextCentredTransparent(frame, 160 + x_offset, y, clipped, color, scale);
}
static void draw_wave_text(uint16_t *frame, const char *text, int y, int scale,
uint16_t color, uint32_t elapsed)
{
unsigned length = 0;
while (text[length] != '\0') ++length;
int x = 160 - (int)length * PET2001_FONT_GLYPH_WIDTH * scale / 2;
const float base_phase =
((float)(elapsed % WAVE_CYCLE_MS) / WAVE_CYCLE_MS) * 6.2831853f;
for (unsigned index = 0; index < length; ++index) {
const int wave_y = y +
(int)(sinf(base_phase + (float)index * 0.55f) * WAVE_HEIGHT);
drawPet2001AsciiCharTransformed(frame, x + 2 + 4 * scale, wave_y + 2 + 4 * scale,
text[index], (float)scale, 0.0f, COLOR_DARKRED);
drawPet2001AsciiCharTransformed(frame, x + 4 * scale, wave_y + 4 * scale,
text[index], (float)scale, 0.0f, color);
x += PET2001_FONT_GLYPH_WIDTH * scale;
}
}
static void draw_transformed_text(uint16_t *frame, const char *text, int y,
int scale, float zoom, float angle,
uint16_t color)
{
drawPet2001TextTransformed(frame, 162, y + (PET2001_FONT_GLYPH_HEIGHT * scale) / 2 + 2,
text, scale, zoom, angle, COLOR_DARKRED);
drawPet2001TextTransformed(frame, 160, y + (PET2001_FONT_GLYPH_HEIGHT * scale) / 2,
text, scale, zoom, angle, color);
}
static void draw_animated_text(uint16_t *frame, uint32_t elapsed)
{
const char *subtitle = messages[message_index];
const unsigned title_length = 9U;
unsigned subtitle_length = 0;
while (subtitle[subtitle_length] != '\0') ++subtitle_length;
drawPet2001TextCentredTransparent(frame, 160, 7, "CODED BY", COLOR_LIGHTGRAY, 1);
const uint8_t title_effect = effect_preset / 11U;
const uint8_t subtitle_effect = effect_preset % 11U;
int title_x = 0;
int subtitle_x = 0;
int title_y = 20;
int subtitle_y = 57;
unsigned title_visible = title_length;
unsigned subtitle_visible = subtitle_length;
uint16_t title_color = COLOR_YELLOW;
uint16_t subtitle_color = COLOR_ORANGE;
float title_angle = 0.0f, subtitle_angle = 0.0f;
float title_zoom = 1.0f, subtitle_zoom = 1.0f;
bool title_wave = false, subtitle_wave = false;
switch (title_effect) {
case 0: title_x = 200 - (int)((elapsed * 55U / 1000U) % 400U); break;
case 1: title_x = (int)((elapsed * 55U / 1000U) % 100U) - 50; break;
case 2: title_y += (int)(sinf((float)elapsed / 445.0f) * 18.0f); break;
case 3: title_wave = true; break;
case 4: title_x = (int)((elapsed / 18U) % 7U) - 3; break;
case 5: title_visible = (elapsed / 130U) % (title_length + 1U); break;
case 6: title_color = (uint16_t[]){COLOR_DARKRED, COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_WHITE}[(elapsed / 180U) % 5U]; break;
case 7: title_angle = sinf((float)elapsed / 382.0f) * 12.0f; break;
case 8: title_zoom = 0.88f + (sinf((float)elapsed / 318.0f) + 1.0f) * 0.10f; break;
case 9: title_y += (int)(18.0f - fminf(18.0f, (float)(elapsed % 2800U) * 18.0f / 700.0f)); break;
case 10: title_visible = (elapsed / 90U) % (title_length + 1U); break;
default: break;
}
switch (subtitle_effect) {
case 0: subtitle_x = 220 - (int)((elapsed * 45U / 1000U) % 440U); break;
case 1: subtitle_x = (int)((elapsed * 55U / 1000U) % 100U) - 50; break;
case 2: subtitle_y += (int)(sinf((float)elapsed / 445.0f) * 30.0f); break;
case 3: subtitle_wave = true; break;
case 4: subtitle_x = (int)((elapsed / 16U) % 7U) - 3; break;
case 5: subtitle_visible = (elapsed / 130U) % (subtitle_length + 1U); break;
case 6: subtitle_color = (uint16_t[]){COLOR_DARKRED, COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_WHITE}[(elapsed / 180U) % 5U]; break;
case 7: subtitle_angle = sinf((float)elapsed / 382.0f) * 12.0f; break;
case 8: subtitle_zoom = 0.88f + (sinf((float)elapsed / 318.0f) + 1.0f) * 0.10f; break;
case 9: subtitle_y += (int)(18.0f - fminf(18.0f, (float)(elapsed % 2800U) * 18.0f / 700.0f)); break;
case 10: subtitle_visible = (elapsed / 90U) % (subtitle_length + 1U); break;
default: break;
}
if (title_wave) {
draw_wave_text(frame, "JD and MI", title_y, 3, title_color, elapsed);
} else if (title_angle != 0.0f || title_zoom != 1.0f) {
draw_transformed_text(frame, "JD and MI", title_y, 3, title_zoom,
title_angle, title_color);
} else {
draw_about_text(frame, "JD and MI", title_y, 3, title_x, title_color, title_visible);
}
if (subtitle_wave) {
draw_wave_text(frame, subtitle, subtitle_y, 1, subtitle_color, elapsed);
} else if (subtitle_angle != 0.0f || subtitle_zoom != 1.0f) {
draw_transformed_text(frame, subtitle, subtitle_y, 1, subtitle_zoom,
subtitle_angle, subtitle_color);
} else {
draw_about_text(frame, subtitle, subtitle_y, 1, subtitle_x, subtitle_color, subtitle_visible);
}
}
void startAbout(uint32_t now_ms)
{
flameEffectInitialize(&fire, heat, FIRE_COLUMNS, FIRE_ROWS, FIRE_PIXEL_WIDTH,
FIRE_PIXEL_HEIGHT, true, esp_random());
select_message();
effect_preset = esp_random() % EFFECT_PRESET_COUNT;
started_at = last_frame = now_ms;
startMoonlight(now_ms);
showing_credits = false;
running = true;
}
void stopAbout(void)
{
stopCredits();
stopMoonlight();
showing_credits = false;
running = false;
}
void updateAbout(uint32_t now_ms)
{
if (!running || showing_credits || now_ms - last_frame < FRAME_MS) return;
updateMoonlight(now_ms);
last_frame = now_ms;
flameEffectUpdate(&fire);
}
void aboutAction(bool next, bool select, uint32_t now_ms)
{
if (!running) return;
if (showing_credits) {
if (creditsAction(next, select)) {
showing_credits = false;
started_at = last_frame = now_ms;
select_message();
startMoonlight(now_ms);
}
return;
}
if (select) {
stopMoonlight();
showing_credits = true;
startCredits();
return;
}
if (next) {
effect_preset = (effect_preset + 1U) % EFFECT_PRESET_COUNT;
started_at = last_frame = now_ms;
}
}
void drawAbout(uint16_t *frame)
{
if (!running) return;
if (showing_credits) {
drawCredits(frame);
return;
}
clear(frame, COLOR_BLACK);
draw_animated_text(frame, last_frame - started_at);
// NULL preserves About's original Doom-style orange flame palette.
flameEffectDraw(frame, &fire, 0, FIRE_TOP, NULL);
// A one-pixel offset gives the PET control label a readable shadow.
drawPet2001TextCentredTransparent(frame, 157, 158, "A NEXT BOOT EXIT", COLOR_DARKGRAY, 2);
drawPet2001TextCentredTransparent(frame, 158, 157, "A NEXT BOOT EXIT", COLOR_LIGHTGRAY, 2);
}