1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
use crate::{Material, ReliefData, ShadingData, TextureData};
/// What one part of a mesh draws with: a material and its maps, over some
/// of the mesh's triangles.
///
/// A slot is a length, not a range.
#[derive(Clone, Debug)]
pub struct Slot {
index_count: u32,
material: Material,
texture: Option<TextureData>,
relief: Option<ReliefData>,
shading: Option<ShadingData>,
emissive: Option<TextureData>,
/// The index of the part naming this slot, absent while it is
/// anonymous.
part: Option<u32>,
}
impl Slot {
/// A slot drawn with `material` over a white default, for the next
/// `index_count` indices.
pub fn new(index_count: u32, material: Material) -> Self {
Self {
index_count,
material,
texture: None,
relief: None,
shading: None,
emissive: None,
part: None,
}
}
/// Samples this slot from `texture`, in place of the white default.
#[must_use]
pub fn textured(mut self, texture: TextureData) -> Self {
self.texture = Some(texture);
self
}
/// The relief is a texture map: `RGB` holds each texel's normal, `+Y` up
/// the map, and `A` its depth where the relief declares one, `1.0` one
/// sprite width, half in front of the sprite and half behind.
///
/// Required if you want a surface lit by normals its own corners do not
/// hold. A billboarded or upright draw reads the normal in the axes the
/// camera turned; every other draw reads it through the derivative
/// basis — the basis its own position and UV derivatives span — and
/// ignores the depth. The relief is windowed like the color texture, so
/// each sheet cell lines up with its own relief cell. A depth also
/// decides what a billboarded or upright draw casts: a texel with no
/// depth casts nothing, and depth under the sprite's own texels, down to
/// its foot, produces a shadow that starts at the ground it is drawn on.
#[must_use]
pub fn relief(mut self, relief: ReliefData) -> Self {
self.relief = Some(relief);
self
}
/// The shading map holds each texel's occlusion in `R`, its roughness in
/// `G` and its metallic in `B`. The roughness and metallic each scale the
/// slot's own lane; the occlusion instead darkens what the texel takes
/// of the frame's sky.
///
/// Required if you want the roughness, the metallic or the sky's own
/// light on one material to differ across the surface. Every light of
/// the frame lands whole, whatever the occlusion holds.
#[must_use]
pub fn shading(mut self, shading: ShadingData) -> Self {
self.shading = Some(shading);
self
}
/// The emissive map is the light this slot casts per texel, scaled by the
/// material's emissive color.
///
/// Required if you want part of a surface to cast light while the rest of
/// it does not. A material casts none by default, so the map alone casts
/// nothing.
#[must_use]
pub fn emissive_map(mut self, emissive: TextureData) -> Self {
self.emissive = Some(emissive);
self
}
/// The number of the mesh's indices this slot covers.
pub fn index_count(&self) -> u32 {
self.index_count
}
/// The material used unless a draw overrides this slot.
pub fn material(&self) -> Material {
self.material
}
/// The pixels this slot samples, absent while it is drawn over white.
pub fn texture(&self) -> Option<&TextureData> {
self.texture.as_ref()
}
/// The same slot named by the part at `part`.
pub(crate) fn named(mut self, part: u32) -> Self {
self.part = Some(part);
self
}
/// The index of the part naming this slot, absent while it is
/// anonymous.
pub(crate) fn part(&self) -> Option<u32> {
self.part
}
/// The relief this slot reads, absent where it has none.
pub(crate) fn relief_map(&self) -> Option<&ReliefData> {
self.relief.as_ref()
}
/// The shading map this slot reads, absent where it has none.
pub(crate) fn shading_map(&self) -> Option<&ShadingData> {
self.shading.as_ref()
}
/// The emissive map this slot reads, absent where it has none.
pub(crate) fn emissive(&self) -> Option<&TextureData> {
self.emissive.as_ref()
}
/// Sets the material, in place of the one it has.
pub(crate) fn set_material(&mut self, material: Material) {
self.material = material;
}
/// Sets the texture, in place of any it has.
pub(crate) fn set_texture(&mut self, texture: TextureData) {
self.texture = Some(texture);
}
/// Sets the relief, in place of any it has.
pub(crate) fn set_relief(&mut self, relief: ReliefData) {
self.relief = Some(relief);
}
/// Sets the shading map, in place of any it has.
pub(crate) fn set_shading(&mut self, shading: ShadingData) {
self.shading = Some(shading);
}
/// Sets the emissive map, in place of any it has.
pub(crate) fn set_emissive_map(&mut self, emissive: TextureData) {
self.emissive = Some(emissive);
}
/// Memory the pixels this slot samples hold.
pub(crate) fn bytes(&self) -> usize {
[
self.texture.as_ref(),
self.relief.as_ref().map(ReliefData::map),
self.shading.as_ref().map(ShadingData::map),
self.emissive.as_ref(),
]
.into_iter()
.flatten()
.map(|texture| texture.pixels().len())
.sum()
}
}