Skip to main content

atmos/kernel/
glyph_fill.rs

1//! グリフ塗りつぶしの区間計算(純粋モジュール)。
2//!
3//! 【2026-10-03】ラスタライザは even-odd 規則(交点を 2 個ずつ組にする)で塗っていた。
4//! TrueType/OpenType の輪郭は **non-zero(巻き数)規則**で塗る決まりで、CJK フォント(Noto Sans JP 等)は
5//! 画を別々の輪郭として**重ねて**作ることが多い。even-odd だと重なりが穴になり、
6//! sugi-lab.net の見出し「主な研究テーマ」の「主」で横画と縦画の交差部が白く抜けていた。
7
8extern crate alloc;
9use alloc::vec::Vec;
10
11/// 1 本の走査線上の交点 (x, 向き) から、塗る区間 [開始, 終了) を non-zero 規則で求める。
12/// 向きは辺が y 増加方向なら +1、減少方向なら -1(輪郭の回り方向の符号。どちら向きを正にしても結果は同じ)。
13/// `crossings` は x 昇順に並べ替えられる。
14pub fn nonzero_spans(crossings: &mut [(f32, i8)], out: &mut Vec<(f32, f32)>) {
15    out.clear();
16    crossings.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(core::cmp::Ordering::Equal));
17    let mut winding: i32 = 0;
18    let mut start = 0.0f32;
19    for &(x, dir) in crossings.iter() {
20        let before = winding;
21        winding += dir as i32;
22        if before == 0 && winding != 0 {
23            start = x;
24        } else if before != 0 && winding == 0 && x > start {
25            out.push((start, x));
26        }
27    }
28}