ilda_idtf/layout.rs
1//! An ILDA file consists of sections which either contain a frame or a color palette. Eachsection
2//! consists of a fixed length header followed by a variable number of data records, which are
3//! either frame points or color palette colors.
4
5use zerocopy::{AsBytes, FromBytes, Unaligned};
6
7/// The endianness of bytes read from and written to the format.
8pub type Endianness = byteorder::BigEndian;
9type I16 = zerocopy::byteorder::I16<Endianness>;
10type U16 = zerocopy::byteorder::U16<Endianness>;
11
12/// The type and data format of the section is defined by the format code.
13///
14/// There are five different formats currently defined.
15///
16/// Format 3 was proposed within the ILDA Technical Committee but was never approved. Therefore,
17/// format 3 is omitted in this ILDA standard.
18///
19/// Formats 0, 1, 4 and 5 define point data. Each point includes X and Y coordinates, andcolor
20/// information. The 3D formats 0 and 4 also include Z (depth) information.
21///
22/// The indexed color formats 0 and 1 use a data format where each point has a Color Indexbetween 0
23/// and 255 used as an index into a color palette. Format 2 specifies the colorpalette for use with
24/// indexed color frames. The true color formats 4 and 5 use a red,green and blue color component
25/// of 8 bits for each point. ILDA files may contain a mix offrames with several
26/// different format codes.
27#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
28#[repr(C)]
29pub struct Format(pub u8);
30
31#[derive(Copy, Clone, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
32#[repr(C)]
33pub struct Name(pub [u8; 8]);
34
35/// Describes the layout of a section of IDTF.
36#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
37#[repr(C)]
38pub struct Header {
39 /// The ASCII letters ILDA, identifying an ILDA format header.
40 pub ilda: [u8; 4],
41 /// Reserved for future use. Must be zeroed.
42 pub reserved: [u8; 3],
43 /// One of the format codes defined in the Format Codes section.
44 pub format: Format,
45 /// Eight ASCII characters with the name of this frame or color palette. If abinary zero is
46 /// encountered, than any characters following the zero SHALL be ignored.
47 pub data_name: Name,
48 /// Eight ASCII characters with the name of the company who created theframe. If a binary zero
49 /// is encountered, than any characters following the zero SHALL beignored.
50 pub company_name: Name,
51 /// Total number of data records (points or colors) that will follow this headerexpressed as an
52 /// unsigned integer (0 – 65535). If the number of records is 0, then this is to be taken as
53 /// the end of file header and nomore data will follow this header. For color palettes, the
54 /// number of records SHALL be between 2 and 256.
55 pub num_records: U16,
56 /// Frame or color palette number. If the frame is part of a group such as an animation
57 /// sequence, thisrepresents the frame number. Counting begins with frame 0. Range is 0 –
58 /// 65534.
59 pub data_number: U16,
60 /// Total frames in this group or sequence. Range is 1 – 65535.
61 ///
62 /// For colorpalettes this SHALL be 0.
63 pub color_or_total_frames: U16,
64 /// The projector number that this frame is to be displayed on. Range is 0 – 255. For single
65 /// projector files this SHOULD be set 0.
66 pub projector_number: u8,
67 /// Reserved for future use. Must be zeroed.
68 pub reserved2: u8,
69}
70
71#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
72#[repr(C)]
73pub struct Coords3d {
74 /// left negative, right positive.
75 pub x: I16,
76 /// down negative, up positive.
77 pub y: I16,
78 /// far negative, near positive.
79 pub z: I16,
80}
81
82#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
83#[repr(C)]
84pub struct Coords2d {
85 /// left negative, right positive.
86 pub x: I16,
87 /// down negative, up positive.
88 pub y: I16,
89}
90
91bitflags! {
92 #[derive(AsBytes, FromBytes, Unaligned)]
93 #[repr(C)]
94 pub struct Status: u8 {
95 /// This bit SHALL be set to 0 for all points except the lastpoint of the image.
96 const LAST_POINT = 0b10000000;
97 /// If this is a 1, then the laser is off (blank). If this is a 0, then thelaser is on
98 /// (draw). Note that all systems SHALL write this bit, even if a particular systemuses the
99 /// color index for blanking/color information.
100 ///
101 /// When reading files, the blanking bit takes precedence over the color from the
102 /// colorpalette or the points RGB values. If the blanking bit is set, all RGB values
103 /// SHOULD betreated as zero.
104 const BLANKING = 0b01000000;
105 }
106}
107
108#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
109#[repr(C)]
110pub struct Color {
111 pub red: u8,
112 pub green: u8,
113 pub blue: u8,
114}
115
116#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
117#[repr(C)]
118pub struct Coords3dIndexedColor {
119 pub coords: Coords3d,
120 pub status: Status,
121 pub color_index: u8,
122}
123
124#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
125#[repr(C)]
126pub struct Coords2dIndexedColor {
127 pub coords: Coords2d,
128 pub status: Status,
129 pub color_index: u8,
130}
131
132#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
133#[repr(C)]
134pub struct ColorPalette {
135 pub color: Color,
136}
137
138#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
139#[repr(C)]
140pub struct Coords3dTrueColor {
141 pub coords: Coords3d,
142 pub status: Status,
143 pub color: Color,
144}
145
146#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, AsBytes, FromBytes, Unaligned)]
147#[repr(C)]
148pub struct Coords2dTrueColor {
149 pub coords: Coords2d,
150 pub status: Status,
151 pub color: Color,
152}
153
154impl Format {
155 pub const COORDS_3D_INDEXED_COLOR: Self = Self(0);
156 pub const COORDS_2D_INDEXED_COLOR: Self = Self(1);
157 pub const COLOR_PALETTE: Self = Self(2);
158 pub const COORDS_3D_TRUE_COLOR: Self = Self(4);
159 pub const COORDS_2D_TRUE_COLOR: Self = Self(5);
160}
161
162impl Name {
163 /// Read the ascii bytes as a UTF8 str.
164 pub fn as_str(&self) -> Result<&str, std::str::Utf8Error> {
165 let len = self.0.iter().position(|&b| b == 0).unwrap_or(self.0.len());
166 std::str::from_utf8(&self.0[..len])
167 }
168}
169
170impl Header {
171 pub const ILDA: [u8; 4] = [0x49, 0x4c, 0x44, 0x41];
172}
173
174impl Status {
175 pub fn is_blanking(&self) -> bool {
176 self.contains(Self::BLANKING)
177 }
178
179 pub fn is_last_point(&self) -> bool {
180 self.contains(Self::LAST_POINT)
181 }
182}
183
184impl std::fmt::Debug for Name {
185 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
186 match self.as_str() {
187 Ok(s) => std::fmt::Debug::fmt(s, f),
188 _ => std::fmt::Debug::fmt(&self.0, f),
189 }
190 }
191}
192
193impl std::fmt::Display for Name {
194 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
195 match self.as_str() {
196 Ok(s) => std::fmt::Display::fmt(s, f),
197 _ => std::fmt::Display::fmt("invalid", f),
198 }
199 }
200}