build-dev / nix-build (push) Successful in 41s
Override the LETTERBOX logical presentation while the scroller is active so it renders into the full physical window. On a 1920x6480 rotated display the scroller now scrolls through all 6480 pixels of vertical space instead of being confined to the 1920x1080 letterbox region. Text scale is unchanged (same font size, same pixel rasterization); more lines are simply visible at once. - onPush: save current logical presentation, switch to DISABLED with real window dimensions - onPop: restore the saved LETTERBOX presentation - resize handler in main.cpp: skip re-apply while scroller is active (it owns its own presentation and restores on pop)
123 lines
4.1 KiB
C++
123 lines
4.1 KiB
C++
#pragma once
|
|
|
|
#include "fibonacci_line_pattern.h"
|
|
#include "page.h"
|
|
#include "scroller_streams.h"
|
|
|
|
#include <SDL3/SDL.h>
|
|
#include <SDL3_ttf/SDL_ttf.h>
|
|
#include <deque>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
struct AppState;
|
|
|
|
// Full-screen page showing proclamation text scrolling vertically using the
|
|
// Fibonacci line-length pattern, per-frequency color palettes, and crossfaded
|
|
// solfeggio audio. Proclamation text is never rendered as human-readable type:
|
|
// every code point is rasterized and permuted into a scrambled glyph tile by
|
|
// the Fibonacci affine map (see scramble/fibonacci_scrambler.h), and words are
|
|
// assembled from those tiles. ESC returns to the previous page (Home).
|
|
class ScrollerPage : public Page {
|
|
public:
|
|
void onPush(AppState& state) override;
|
|
void onResume(AppState& state) override;
|
|
void onPause(AppState& state) override;
|
|
void onPop(AppState& state) override;
|
|
void handleEvent(const SDL_Event& event) override;
|
|
void update(float dt) override;
|
|
void render(SDL_Renderer* renderer) override;
|
|
|
|
private:
|
|
struct WordItem {
|
|
SDL_Texture* texture = nullptr;
|
|
std::string text;
|
|
float width = 0;
|
|
float height = 0;
|
|
float x = 0; // relative to the line's left edge
|
|
float y = 0;
|
|
};
|
|
|
|
struct ScrollerLine {
|
|
std::vector<WordItem> words;
|
|
float width = 0;
|
|
uint8_t r = 255;
|
|
uint8_t g = 255;
|
|
uint8_t b = 255;
|
|
};
|
|
|
|
struct CachedWord {
|
|
SDL_Texture* texture = nullptr;
|
|
float width = 0;
|
|
float height = 0;
|
|
};
|
|
|
|
// A single glyph's scrambled tile -- [This implementation] rendering
|
|
// decision: scrambling is per code point so any glyph in the proclamation
|
|
// set is permuted exactly once per font size, then reused by every word
|
|
// that contains it.
|
|
// `surface` is the N x N (N = max(glyphW, glyphH)) RGBA8888 canvas
|
|
// produced by the Fibonacci affine scrambler. glyphW x glyphH is the
|
|
// size of the ORIGINAL, unscrambled glyph (the top-left W x H
|
|
// sub-rectangle of the tile, matching the crop-window display
|
|
// convention); word assembly blits exactly that crop. `advance` is the
|
|
// glyph's unmodified TTF advance width, so per-glyph assembly keeps word
|
|
// layout identical to plain text rendering. Every glyph surface carries
|
|
// the font's full line height, so crops align on the shared baseline.
|
|
struct CharEntry {
|
|
SDL_Surface* surface = nullptr;
|
|
float glyphW = 0;
|
|
float glyphH = 0;
|
|
float advance = 0;
|
|
};
|
|
|
|
void buildStreams(AppState& state);
|
|
void createFont(AppState& state);
|
|
void createPatterns();
|
|
int computePeakWordCount(const std::vector<std::string>& words) const;
|
|
void destroyResources();
|
|
void rebuildWordTextures();
|
|
void prefillLines();
|
|
bool addLineAt(float baseY);
|
|
void advanceStream();
|
|
void switchAudioForCurrentStream();
|
|
void updateAutoVelocity(float dt);
|
|
void ensureWordTexture(const std::string& word);
|
|
void ensureCharTexture(const std::string& glyph);
|
|
void clearCharTextures();
|
|
float measureWidth(const std::string& text) const;
|
|
std::string audioFilePath(const std::string& filename) const;
|
|
|
|
AppState* state_ = nullptr;
|
|
|
|
std::vector<radiantwave::scroller::ProclamationStream> streams_;
|
|
std::vector<radiantwave::scroller::StreamColor> fallbackPalette_;
|
|
std::vector<radiantwave::FibonacciLinePattern> patterns_;
|
|
int streamIndex_ = 0;
|
|
bool prefilling_ = false;
|
|
|
|
TTF_Font* font_ = nullptr;
|
|
int fontPxSize_ = 32;
|
|
float lineHeight_ = 0;
|
|
float spaceWidth_ = 0;
|
|
float screenW_ = 0;
|
|
float screenH_ = 0;
|
|
float maxLineWidth_ = 0;
|
|
|
|
std::deque<ScrollerLine> lines_;
|
|
std::unordered_map<std::string, CachedWord> wordTextures_;
|
|
std::unordered_map<std::string, CharEntry> charTextures_;
|
|
|
|
float scrollOffset_ = 0;
|
|
float velocity_ = -2750.0f;
|
|
float velocityStep_ = 100.0f;
|
|
float velocityDelay_ = 2.5f;
|
|
int velocityState_ = 0;
|
|
float velocityTimer_ = 0.0f;
|
|
|
|
int savedLogicalW_ = 0;
|
|
int savedLogicalH_ = 0;
|
|
SDL_RendererLogicalPresentation savedMode_ = SDL_LOGICAL_PRESENTATION_DISABLED;
|
|
};
|