Grey: a level as an opaque colour¶
A grey level as an opaque colour, (g, g, g, 1) with g = clamp(level, 0, 1): 0 black, 1 white.
A display kind of the specification, section 11. Source: lusine's grey as lusine drew it before this kernel. Checked against a reference in numpy, which has its own tests.
- Source
- lusine's grey as its GLSL back end lowered it.
- Proof
- limit, invariant.
grey.trait
namespace lusine.display;
vector<float, 4> grey(float level)
{
let g = clamp(level, 0.0, 1.0);
return vector<float, 4>(g, g, g, 1.0);
}
A grey level as an opaque colour, (g, g, g, 1) with g = clamp(level, 0, 1): 0 black, 1 white.
In [1]:
Copied!
import os, sys
root = os.getcwd()
while not os.path.isfile(os.path.join(root, 'docsite.json')):
root = os.path.dirname(root)
sys.path.insert(0, os.path.join(root, 'tools'))
import numpy as np
import matplotlib.pyplot as plt
from lusine import trait_run
EPS = float(np.finfo(np.float32).eps) # Trait's float is binary32
import os, sys
root = os.getcwd()
while not os.path.isfile(os.path.join(root, 'docsite.json')):
root = os.path.dirname(root)
sys.path.insert(0, os.path.join(root, 'tools'))
import numpy as np
import matplotlib.pyplot as plt
from lusine import trait_run
EPS = float(np.finfo(np.float32).eps) # Trait's float is binary32
The kernel¶
The law as the library states it.
In [2]:
Copied!
print(trait_run.source('display/grey.trait'))
print(trait_run.source('display/grey.trait'))
// lusine.display.grey: a grey level as an opaque colour, (g, g, g, 1) with g = clamp(level, 0, 1): 0 black, 1 white.
// A display kind of the specification, section 11.
// Source: lusine's grey as lusine drew it before this kernel.
// Checked against a reference in numpy, which has its own tests.
namespace lusine.display;
vector<float, 4> grey(float level)
{
let g = clamp(level, 0.0, 1.0);
return vector<float, 4>(g, g, g, 1.0);
}
The program¶
Each section runs the kernel over a lattice of items, one a level: the host sets it, and main() binds the kernel over the items.
In [3]:
Copied!
print(trait_run.law_program('display/grey.trait', 'grey'))
def grey(level):
return trait_run.law('display/grey.trait', 'grey', level=level)
print(trait_run.law_program('display/grey.trait', 'grey'))
def grey(level):
return trait_run.law('display/grey.trait', 'grey', level=level)
namespace probe;
lusine.version version = { { number = 1 } };
struct item {
host float level;
vector<float, 4> result_0;
};
lattice<item, 1> items(spacing = 1 m, boundary = wall);
void main() { items.result_0 = lusine.display.grey(items.level); }
Limit: black, white and beyond¶
0 is black and 1 white, opaque; a level below 0 is black and above 1 white.
In [4]:
Copied!
c = grey([0.0, 1.0, -0.5, 7.0, -1e30, 1e30])
assert np.array_equal(c, [[0, 0, 0, 1], [1, 1, 1, 1], [0, 0, 0, 1], [1, 1, 1, 1], [0, 0, 0, 1], [1, 1, 1, 1]]), c
print(c)
c = grey([0.0, 1.0, -0.5, 7.0, -1e30, 1e30])
assert np.array_equal(c, [[0, 0, 0, 1], [1, 1, 1, 1], [0, 0, 0, 1], [1, 1, 1, 1], [0, 0, 0, 1], [1, 1, 1, 1]]), c
print(c)
[[0. 0. 0. 1.] [1. 1. 1. 1.] [0. 0. 0. 1.] [1. 1. 1. 1.] [0. 0. 0. 1.] [1. 1. 1. 1.]]
Invariant: the level itself¶
Inside 0 to 1, each of red, green and blue is the level, bit for bit, and alpha is 1.
In [5]:
Copied!
level = np.float32(np.linspace(0.0, 1.0, 257)).astype(float)
c = grey(level)
assert all(np.array_equal(c[:, i], level) for i in range(3)) and np.all(c[:, 3] == 1.0)
fig, ax = plt.subplots(figsize=(7, 0.8))
ax.imshow(c[None, :, :3], aspect='auto', extent=(0, 1, 0, 1))
ax.set_yticks([])
ax.set_xlabel('level')
plt.show()
level = np.float32(np.linspace(0.0, 1.0, 257)).astype(float)
c = grey(level)
assert all(np.array_equal(c[:, i], level) for i in range(3)) and np.all(c[:, 3] == 1.0)
fig, ax = plt.subplots(figsize=(7, 0.8))
ax.imshow(c[None, :, :3], aspect='auto', extent=(0, 1, 0, 1))
ax.set_yticks([])
ax.set_xlabel('level')
plt.show()