Files
rspektrum/src/render.h
T
tyler 724956278d fix: bake UI font atlas at physical DPI size so text isn't skinny on standard-DPI
The font atlas was rasterized once at a fixed 16px and point-filtered, then
scaled to a logical size at draw time. On HiDPI it got upscaled (acceptable);
on standard-DPI it got downscaled, and point filtering dropped rows/columns of
the anti-aliased glyphs, thinning stems into a faint "hyper-skinny" look.

Bake the atlas at the real physical size text is drawn at
(16 * GetUIScale() * GetWindowScaleDPI().y), quantized to 4px steps, and rebuild
it via EnsureUIFont() once per frame when that density changes (resize, or
moving between monitors of different DPI). Use mipmaps + trilinear filtering so
downsampling stays smooth. Call sites are unchanged: DrawTextEx still scales the
atlas glyph to the same logical size, only the backing resolution differs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 18:27:35 -07:00

60 lines
2.7 KiB
C

// render.h - UI scaling, colormaps, spectrogram texture generation, drawing
#ifndef RENDER_H
#define RENDER_H
#include "spectrogram_types.h"
// --- UI scaling & scaled text ---
float GetUIScale(void);
void DrawTextScaled(const char* text, float x, float y, float baseSize, Color color);
float MeasureTextScaled(const char* text, float baseSize);
// --- DPI-aware UI font ---
// InitUIFont remembers the TTF path and bakes the first atlas; EnsureUIFont
// rebuilds it (cheap no-op when unchanged) whenever the effective pixel density
// (window UI scale * monitor DPI scale) shifts, keeping text crisp on any
// display instead of thinning out on standard-DPI screens. Call EnsureUIFont
// once per frame before drawing text.
void InitUIFont(const char* path);
void EnsureUIFont(void);
// --- Colormaps ---
void GenerateColormapTexture(void);
const char* ColormapName(ColormapType type);
// --- Spectrogram texture ---
// GenerateSpectrogramTexture recomputes the synchrosqueezed reassignment (use
// when the STFT changes). ColorizeSpectrogram only re-maps the cached
// reassignment to colors (use for dB-floor / colormap changes).
void GenerateSpectrogramTexture(StftResult* stft, Image* image, Texture2D* texture);
void ColorizeSpectrogram(Image* image, Texture2D* texture);
// --- Headless (no-GL) spectrogram + annotation rendering ---
// BuildSpectrogramImageCPU fills `image` with the colorized spectrogram with no
// texture upload, so it runs with no window / no X server. LoadFontCPU returns
// a Font usable by ImageDrawTextEx without a GL context (glyphCount==0 on
// failure). DrawAnnotationsToImage paints the mLnL overlay onto a full-
// resolution spectrogram Image, honoring the kind filter and resting opacity.
void BuildSpectrogramImageCPU(StftResult* stft, Image* image);
Font LoadFontCPU(const char* path, int baseSize);
void DrawAnnotationsToImage(Image* img, Font font);
// --- On-screen drawing (operate on the global app state) ---
void DrawSpectrogramGrid(Rectangle bounds, int numCellsX, int numCellsY, Color color);
void DrawLabels(Rectangle bounds);
void DrawSelection(Rectangle bounds);
void DrawSelectionDrag(Rectangle bounds);
void DrawCursorReadout(Rectangle bounds);
void DrawMarkers(Rectangle bounds);
void DrawSpectrumPanel(Rectangle bounds);
void DrawPlayhead(Rectangle bounds);
void DrawAnnotations(Rectangle bounds);
// Annotation timeline lane. Updates app.hoveredTimelineEvent and
// app.selectedAnnotation in response to mouse interaction in `lane`.
void DrawTimeline(Rectangle lane);
// Time-only annotation overlay rendered on top of the waveform scope.
// Shares opacity/selection state with the spectrogram overlay.
void DrawAnnotationsOnScope(Rectangle scopeBounds);
#endif // RENDER_H