tawasuyu

tawasuyu/llimphi

Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.

Rust 660Markdown 302TOML 157RON 312382 Definiciones

⎇ 168cd187519c0ad575d3ce63baee2f164c38d9d1 escena_patron.rs Rust · 184 líneas · 7.2 KB Historia Quién tocó qué crudo

chore: refresco desde el monorepo — 128 miembros, los 76 widgets y los 11 módulos b3f12e136 · Sergio ·

1// =============================================================================
2//  escena_patron.rs — el árbol de prueba que se pinta por LOS DOS caminos.
3// -----------------------------------------------------------------------------
4//  Llimphi tiene dos rasterizadores: `vello` (GPU, lo que corre en Linux) y
5//  `vello_cpu` vía `llimphi-cpu` (lo que corre en el kernel bare-metal de wawa).
6//  El compositor es el MISMO —`paint` emite las mismas órdenes— pero **nadie
7//  había comparado nunca la salida**. O sea que la UI de wawa podía verse
8//  distinta de la de Linux y no había forma de enterarse sin bootear y mirar.
9//
10//  Este archivo se **incluye con `include!`** desde los dos lados, y ésa no es
11//  una maña sino la única forma: los dos backends de `llimphi-text` son
12//  excluyentes (`cpu` vs `vello`), así que un solo binario no puede linkear los
13//  dos y `llimphi-wawa` vive en un workspace aparte justamente por eso. Un
14//  archivo compartido es lo que garantiza que las dos corridas pinten el mismo
15//  árbol y no dos árboles parecidos.
16//
17//  Sólo se usa la API de `llimphi-compositor`, que compila igual en los dos
18//  perfiles. Los dos sitios que lo incluyen corren en el anfitrión (el volcador
19//  de wawa con `--features std`), así que `Vec` de `std` está bien: lo que se
20//  comparte es el ÁRBOL, no el perfil sin sistema operativo.
21// =============================================================================
22
23use llimphi_compositor::llimphi_layout::taffy::prelude::{
24    length, percent, FlexDirection, Size, Style,
25};
26use llimphi_compositor::llimphi_layout::taffy::Rect as Insets;
27use llimphi_compositor::peniko::Color;
28use llimphi_compositor::{Shadow, View};
29
30/// Tamaño de todos los patrones. Chico a propósito: lo que se compara es el
31/// **rasterizado**, y un lienzo grande sólo multiplica los bytes del volcado.
32pub const ANCHO: u32 = 200;
33pub const ALTO: u32 = 150;
34
35fn caja<Msg: Clone>(w: f32, h: f32) -> View<Msg> {
36    View::<Msg>::new(Style {
37        size: Size { width: length(w), height: length(h) },
38        ..Default::default()
39    })
40}
41
42fn raiz<Msg: Clone>(hijos: Vec<View<Msg>>) -> View<Msg> {
43    View::<Msg>::new(Style {
44        flex_direction: FlexDirection::Column,
45        size: Size { width: percent(1.0_f32), height: percent(1.0_f32) },
46        gap: Size { width: length(0.0_f32), height: length(6.0_f32) },
47        padding: Insets {
48            left: length(8.0_f32),
49            right: length(8.0_f32),
50            top: length(8.0_f32),
51            bottom: length(8.0_f32),
52        },
53        ..Default::default()
54    })
55    .fill(Color::from_rgba8(18, 18, 24, 255))
56    .children(hijos)
57}
58
59/// Los patrones, **separados por rasgo**. Que vayan sueltos y no todos en un
60/// cuadro es deliberado: si los dos caminos divergen, el número por patrón dice
61/// **en qué** divergen. Un solo número global diría «difieren» y nada más.
62pub fn patrones<Msg: Clone>() -> Vec<(&'static str, View<Msg>)> {
63    let mut v = Vec::new();
64
65    // 1. Rectángulos alineados a la grilla: sin AA de por medio. Si esto ya
66    //    difiere, el problema no es el antialiasing sino el color o el volcado.
67    v.push((
68        "rects",
69        raiz(vec![
70            caja(80.0, 30.0).fill(Color::from_rgba8(220, 60, 60, 255)),
71            caja(120.0, 25.0).fill(Color::from_rgba8(60, 200, 120, 255)),
72            caja(40.0, 40.0).fill(Color::from_rgba8(80, 120, 240, 255)),
73        ]),
74    ));
75
76    // 2. Esquinas redondeadas y borde: acá sí entra el antialiasing, que es
77    //    donde dos rasterizadores distintos tienen todo el derecho a diferir.
78    v.push((
79        "radios",
80        raiz(vec![
81            caja(90.0, 40.0)
82                .fill(Color::from_rgba8(200, 200, 220, 255))
83                .radius(12.0),
84            caja(90.0, 40.0)
85                .fill(Color::from_rgba8(40, 40, 60, 255))
86                .radius(6.0)
87                .border(2.0, Color::from_rgba8(240, 180, 60, 255)),
88        ]),
89    ));
90
91    // 3. Alpha y capas: `alpha` abre una capa en los dos backends, y componer
92    //    capas es donde una diferencia de orden se nota entera.
93    v.push((
94        "alpha",
95        raiz(vec![
96            caja(150.0, 50.0)
97                .fill(Color::from_rgba8(240, 80, 40, 255))
98                .alpha(0.5)
99                .children(vec![caja(60.0, 30.0)
100                    .fill(Color::from_rgba8(40, 240, 200, 255))]),
101            caja(150.0, 40.0).fill(Color::from_rgba8(90, 90, 240, 128)),
102        ]),
103    ));
104
105    // 4. Sombra: un blur, o sea el rasgo con más aritmética de los cuatro.
106    v.push((
107        "sombra",
108        raiz(vec![caja(110.0, 60.0)
109            .fill(Color::from_rgba8(230, 230, 240, 255))
110            .radius(10.0)
111            .shadow(Shadow {
112                color: Color::from_rgba8(0, 0, 0, 160),
113                blur: 10.0,
114                dx: 3.0,
115                dy: 4.0,
116                spread: 0.0,
117            })]),
118    ));
119
120    // 5. Texto. La fuente va embebida (`include_bytes!` en `llimphi-text`), así
121    //    que los dos caminos shapean con el MISMO archivo y lo que quede es
122    //    diferencia de rasterizado de glifos, no de tipografía.
123    v.push((
124        "texto",
125        raiz(vec![
126            View::<Msg>::new(Style::default()).text(
127                "Hola wawa — jgpqy",
128                18.0,
129                Color::from_rgba8(240, 240, 250, 255),
130            ),
131            View::<Msg>::new(Style::default()).text(
132                "renglón chico 0123456789",
133                11.0,
134                Color::from_rgba8(180, 200, 240, 255),
135            ),
136        ]),
137    ));
138
139    // 6. **La escalera de tamaños de texto.** Existe para decidir una pregunta
140    //    concreta: la divergencia del texto entre los dos rasterizadores, ¿es
141    //    de la ORLA o es SISTEMÁTICA?
142    //
143    //    La tinta de un glifo crece con el área (≈ s²) y su borde con el
144    //    perímetro (≈ s). Si la diferencia viene sólo del antialiasing del
145    //    contorno, su peso relativo tiene que caer como 1/s al agrandar la
146    //    letra. Si en cambio se mantiene, no es el borde: es que un lado pinta
147    //    la cobertura distinto en todo el glifo, y eso sí sería un problema.
148    //
149    //    Una sola letra por patrón, y con curvas: menos glifos, menos ruido.
150    for tam in [11.0f32, 18.0, 48.0, 96.0] {
151        v.push((
152            match tam as u32 {
153                11 => "texto_11",
154                18 => "texto_18",
155                48 => "texto_48",
156                _ => "texto_96",
157            },
158            raiz(vec![View::<Msg>::new(Style::default()).text(
159                "Ooo",
160                tam,
161                Color::from_rgba8(255, 255, 255, 255),
162            )]),
163        ));
164    }
165
166    // 7. Texto separado por REPERTORIO, no por tamaño: ASCII puro contra
167    //    caracteres que pueden no estar en las fuentes embebidas.
168    for (nombre, cadena) in [
169        ("texto_ascii", "Hamburgefonstiv 0123"),
170        ("texto_acentos", "renglon ñáéíóú"),
171        ("texto_raya", "guion — largo"),
172    ] {
173        v.push((
174            nombre,
175            raiz(vec![View::<Msg>::new(Style::default()).text(
176                cadena,
177                18.0,
178                Color::from_rgba8(255, 255, 255, 255),
179            )]),
180        ));
181    }
182
183    v
184}