Skip to main content

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}