| 1 | //! How to write samples (a grid of `f32`, `f16` or `u32` values).
|
| 2 |
|
| 3 | use crate::meta::attribute::{LevelMode, SampleType, TileDescription};
|
| 4 | use crate::meta::header::Header;
|
| 5 | use crate::block::lines::LineRefMut;
|
| 6 | use crate::image::{FlatSamples, Levels, RipMaps};
|
| 7 | use crate::math::{Vec2, RoundingMode};
|
| 8 | use crate::meta::{rip_map_levels, mip_map_levels, rip_map_indices, mip_map_indices, BlockDescription};
|
| 9 |
|
| 10 | /// Enable an image with this sample grid to be written to a file.
|
| 11 | /// Also can contain multiple resolution levels.
|
| 12 | /// Usually contained within `Channels`.
|
| 13 | pub trait WritableSamples<'slf> {
|
| 14 | // fn is_deep(&self) -> bool;
|
| 15 |
|
| 16 | /// Generate the file meta data regarding the number type of this storage
|
| 17 | fn sample_type(&self) -> SampleType;
|
| 18 |
|
| 19 | /// Generate the file meta data regarding resolution levels
|
| 20 | fn infer_level_modes(&self) -> (LevelMode, RoundingMode);
|
| 21 |
|
| 22 | /// The type of the temporary writer for this sample storage
|
| 23 | type Writer: SamplesWriter;
|
| 24 |
|
| 25 | /// Create a temporary writer for this sample storage
|
| 26 | fn create_samples_writer(&'slf self, header: &Header) -> Self::Writer;
|
| 27 | }
|
| 28 |
|
| 29 | /// Enable an image with this single level sample grid to be written to a file.
|
| 30 | /// Only contained within `Levels`.
|
| 31 | pub trait WritableLevel<'slf> {
|
| 32 |
|
| 33 | /// Generate the file meta data regarding the number type of these samples
|
| 34 | fn sample_type(&self) -> SampleType;
|
| 35 |
|
| 36 | /// The type of the temporary writer for this single level of samples
|
| 37 | type Writer: SamplesWriter;
|
| 38 |
|
| 39 | /// Create a temporary writer for this single level of samples
|
| 40 | fn create_level_writer(&'slf self, size: Vec2<usize>) -> Self::Writer;
|
| 41 | }
|
| 42 |
|
| 43 | /// A temporary writer for one or more resolution levels containing samples
|
| 44 | pub trait SamplesWriter: Sync {
|
| 45 |
|
| 46 | /// Deliver a single short horizontal list of samples for a specific channel.
|
| 47 | fn extract_line(&self, line: LineRefMut<'_>);
|
| 48 | }
|
| 49 |
|
| 50 | /// A temporary writer for a predefined non-deep sample storage
|
| 51 | #[derive (Debug, Copy, Clone, PartialEq)]
|
| 52 | pub struct FlatSamplesWriter<'samples> {
|
| 53 | resolution: Vec2<usize>, // respects resolution level
|
| 54 | samples: &'samples FlatSamples
|
| 55 | }
|
| 56 |
|
| 57 |
|
| 58 |
|
| 59 | // used if no layers are used and the flat samples are directly inside the channels
|
| 60 | impl<'samples> WritableSamples<'samples> for FlatSamples {
|
| 61 | fn sample_type(&self) -> SampleType {
|
| 62 | match self {
|
| 63 | FlatSamples::F16(_) => SampleType::F16,
|
| 64 | FlatSamples::F32(_) => SampleType::F32,
|
| 65 | FlatSamples::U32(_) => SampleType::U32,
|
| 66 | }
|
| 67 | }
|
| 68 |
|
| 69 | fn infer_level_modes(&self) -> (LevelMode, RoundingMode) { (LevelMode::Singular, RoundingMode::Down) }
|
| 70 |
|
| 71 | type Writer = FlatSamplesWriter<'samples>; //&'s FlatSamples;
|
| 72 | fn create_samples_writer(&'samples self, header: &Header) -> Self::Writer {
|
| 73 | FlatSamplesWriter {
|
| 74 | resolution: header.layer_size,
|
| 75 | samples: self
|
| 76 | }
|
| 77 | }
|
| 78 | }
|
| 79 |
|
| 80 | // used if layers are used and the flat samples are inside the levels
|
| 81 | impl<'samples> WritableLevel<'samples> for FlatSamples {
|
| 82 | fn sample_type(&self) -> SampleType {
|
| 83 | match self {
|
| 84 | FlatSamples::F16(_) => SampleType::F16,
|
| 85 | FlatSamples::F32(_) => SampleType::F32,
|
| 86 | FlatSamples::U32(_) => SampleType::U32,
|
| 87 | }
|
| 88 | }
|
| 89 |
|
| 90 | type Writer = FlatSamplesWriter<'samples>;
|
| 91 | fn create_level_writer(&'samples self, size: Vec2<usize>) -> Self::Writer {
|
| 92 | FlatSamplesWriter {
|
| 93 | resolution: size,
|
| 94 | samples: self
|
| 95 | }
|
| 96 | }
|
| 97 | }
|
| 98 |
|
| 99 | impl<'samples> SamplesWriter for FlatSamplesWriter<'samples> {
|
| 100 | fn extract_line(&self, line: LineRefMut<'_>) {
|
| 101 | let image_width: usize = self.resolution.width(); // header.layer_size.width();
|
| 102 | debug_assert_ne!(image_width, 0, "image width calculation bug" );
|
| 103 |
|
| 104 | let start_index: usize = line.location.position.y() * image_width + line.location.position.x();
|
| 105 | let end_index: usize = start_index + line.location.sample_count;
|
| 106 |
|
| 107 | debug_assert!(
|
| 108 | start_index < end_index && end_index <= self.samples.len(),
|
| 109 | "for resolution {:?}, this is an invalid line: {:?}" ,
|
| 110 | self.resolution, line.location
|
| 111 | );
|
| 112 |
|
| 113 | match self.samples {
|
| 114 | FlatSamples::F16(samples) => line.write_samples_from_slice(&samples[start_index .. end_index]),
|
| 115 | FlatSamples::F32(samples) => line.write_samples_from_slice(&samples[start_index .. end_index]),
|
| 116 | FlatSamples::U32(samples) => line.write_samples_from_slice(&samples[start_index .. end_index]),
|
| 117 | }.expect(msg:"writing line bytes failed" );
|
| 118 | }
|
| 119 | }
|
| 120 |
|
| 121 |
|
| 122 | impl<'samples, LevelSamples> WritableSamples<'samples> for Levels<LevelSamples>
|
| 123 | where LevelSamples: WritableLevel<'samples>
|
| 124 | {
|
| 125 | fn sample_type(&self) -> SampleType {
|
| 126 | let sample_type = self.levels_as_slice().first().expect("no levels found" ).sample_type();
|
| 127 |
|
| 128 | debug_assert!(
|
| 129 | self.levels_as_slice().iter().skip(1).all(|ty| ty.sample_type() == sample_type),
|
| 130 | "sample types must be the same across all levels"
|
| 131 | );
|
| 132 |
|
| 133 | sample_type
|
| 134 | }
|
| 135 |
|
| 136 | fn infer_level_modes(&self) -> (LevelMode, RoundingMode) {
|
| 137 | match self {
|
| 138 | Levels::Singular(_) => (LevelMode::Singular, RoundingMode::Down),
|
| 139 | Levels::Mip { rounding_mode, .. } => (LevelMode::MipMap, *rounding_mode),
|
| 140 | Levels::Rip { rounding_mode, .. } => (LevelMode::RipMap, *rounding_mode),
|
| 141 | }
|
| 142 | }
|
| 143 |
|
| 144 | type Writer = LevelsWriter<LevelSamples::Writer>;
|
| 145 | fn create_samples_writer(&'samples self, header: &Header) -> Self::Writer {
|
| 146 | let rounding = match header.blocks {
|
| 147 | BlockDescription::Tiles(TileDescription { rounding_mode, .. }) => Some(rounding_mode),
|
| 148 | BlockDescription::ScanLines => None,
|
| 149 | };
|
| 150 |
|
| 151 | LevelsWriter {
|
| 152 | levels: match self {
|
| 153 | Levels::Singular(level) => Levels::Singular(level.create_level_writer(header.layer_size)),
|
| 154 | Levels::Mip { level_data, rounding_mode } => {
|
| 155 | debug_assert_eq!(
|
| 156 | level_data.len(),
|
| 157 | mip_map_indices(rounding.expect("mip maps only with tiles" ), header.layer_size).count(),
|
| 158 | "invalid mip map count"
|
| 159 | );
|
| 160 |
|
| 161 | Levels::Mip { // TODO store level size in image??
|
| 162 | rounding_mode: *rounding_mode,
|
| 163 | level_data: level_data.iter()
|
| 164 | .zip(mip_map_levels(rounding.expect("mip maps only with tiles" ), header.layer_size))
|
| 165 | // .map(|level| level.create_samples_writer(header))
|
| 166 | .map(|(level, (_level_index, level_size))| level.create_level_writer(level_size))
|
| 167 | .collect()
|
| 168 | }
|
| 169 | },
|
| 170 | Levels::Rip { level_data, rounding_mode } => {
|
| 171 | debug_assert_eq!(level_data.map_data.len(), level_data.level_count.area(), "invalid rip level count" );
|
| 172 | debug_assert_eq!(
|
| 173 | level_data.map_data.len(),
|
| 174 | rip_map_indices(rounding.expect("rip maps only with tiles" ), header.layer_size).count(),
|
| 175 | "invalid rip map count"
|
| 176 | );
|
| 177 |
|
| 178 | Levels::Rip {
|
| 179 | rounding_mode: *rounding_mode,
|
| 180 | level_data: RipMaps {
|
| 181 | level_count: level_data.level_count,
|
| 182 | map_data: level_data.map_data.iter()
|
| 183 | .zip(rip_map_levels(rounding.expect("rip maps only with tiles" ), header.layer_size))
|
| 184 | .map(|(level, (_level_index, level_size))| level.create_level_writer(level_size))
|
| 185 | .collect(),
|
| 186 | }
|
| 187 | }
|
| 188 | }
|
| 189 | }
|
| 190 | }
|
| 191 | }
|
| 192 | }
|
| 193 |
|
| 194 | /// A temporary writer for multiple resolution levels
|
| 195 | #[derive (Debug, Clone, Eq, PartialEq)]
|
| 196 | pub struct LevelsWriter<SamplesWriter> {
|
| 197 | levels: Levels<SamplesWriter>,
|
| 198 | }
|
| 199 |
|
| 200 | impl<Samples> SamplesWriter for LevelsWriter<Samples> where Samples: SamplesWriter {
|
| 201 | fn extract_line(&self, line: LineRefMut<'_>) {
|
| 202 | self.levels.get_level(line.location.level).expect(msg:"invalid level index" ) // TODO compute level size from line index??
|
| 203 | .extract_line(line)
|
| 204 | }
|
| 205 | }
|
| 206 | |