blob: 61cacf0bc9a43e37f1d605a0f4474325d77a0137 [file] [log] [blame]
// Copyright 2022 The Vello authors
// SPDX-License-Identifier: Apache-2.0 OR MIT
//! Create a lookup table of half-plane sample masks.
// Width is number of discrete translations
const MASK_WIDTH: usize = 32;
// Height is the number of discrete slopes
const MASK_HEIGHT: usize = 32;
const PATTERN: [u8; 8] = [0, 5, 3, 7, 1, 4, 6, 2];
fn one_mask(slope: f64, mut translation: f64, is_pos: bool) -> u8 {
if is_pos {
translation = 1. - translation;
}
let mut result = 0;
for (i, item) in PATTERN.iter().enumerate() {
let mut y = (i as f64 + 0.5) * 0.125;
let x = (*item as f64 + 0.5) * 0.125;
if !is_pos {
y = 1. - y;
}
if (x - (1.0 - translation)) * (1. - slope) - (y - translation) * slope >= 0. {
result |= 1 << i;
}
}
result
}
/// Make a lookup table of half-plane masks.
///
/// The table is organized into two blocks each with MASK_HEIGHT/2 slopes.
/// The first block is negative slopes (x decreases as y increates),
/// the second as positive.
pub fn make_mask_lut() -> Vec<u8> {
(0..MASK_WIDTH * MASK_HEIGHT)
.map(|i| {
const HALF_HEIGHT: usize = MASK_HEIGHT / 2;
let u = i % MASK_WIDTH;
let v = i / MASK_WIDTH;
let is_pos = v >= HALF_HEIGHT;
let y = ((v % HALF_HEIGHT) as f64 + 0.5) * (1.0 / HALF_HEIGHT as f64);
let x = (u as f64 + 0.5) * (1.0 / MASK_WIDTH as f64);
one_mask(y, x, is_pos)
})
.collect()
}
// Width is number of discrete translations
const MASK16_WIDTH: usize = 64;
// Height is the number of discrete slopes
const MASK16_HEIGHT: usize = 64;
// This is based on the [D3D11 standard sample pattern].
//
// [D3D11 standard sample pattern]: https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_standard_multisample_quality_levels
const PATTERN_16: [u8; 16] = [1, 8, 4, 11, 15, 7, 3, 12, 0, 9, 5, 13, 2, 10, 6, 14];
fn one_mask_16(slope: f64, mut translation: f64, is_pos: bool) -> u16 {
if is_pos {
translation = 1. - translation;
}
let mut result = 0;
for (i, item) in PATTERN_16.iter().enumerate() {
let mut y = (i as f64 + 0.5) * 0.0625;
let x = (*item as f64 + 0.5) * 0.0625;
if !is_pos {
y = 1. - y;
}
if (x - (1.0 - translation)) * (1. - slope) - (y - translation) * slope >= 0. {
result |= 1 << i;
}
}
result
}
/// Make a lookup table of half-plane masks.
///
/// The table is organized into two blocks each with MASK16_HEIGHT/2 slopes.
/// The first block is negative slopes (x decreases as y increates),
/// the second as positive.
pub fn make_mask_lut_16() -> Vec<u8> {
let v16 = (0..MASK16_WIDTH * MASK16_HEIGHT)
.map(|i| {
const HALF_HEIGHT: usize = MASK16_HEIGHT / 2;
let u = i % MASK16_WIDTH;
let v = i / MASK16_WIDTH;
let is_pos = v >= HALF_HEIGHT;
let y = ((v % HALF_HEIGHT) as f64 + 0.5) * (1.0 / HALF_HEIGHT as f64);
let x = (u as f64 + 0.5) * (1.0 / MASK16_WIDTH as f64);
one_mask_16(y, x, is_pos)
})
.collect::<Vec<_>>();
// This annoyingly makes another copy. We can avoid that by pushing two
// bytes per iteration of the above loop.
bytemuck::cast_slice(&v16).into()
}