Refactor goo format
This commit is contained in:
189
Cargo.lock
generated
189
Cargo.lock
generated
@@ -30,6 +30,55 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1"
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.86"
|
||||
@@ -172,12 +221,58 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
||||
|
||||
[[package]]
|
||||
name = "common"
|
||||
version = "0.1.0"
|
||||
@@ -314,7 +409,10 @@ dependencies = [
|
||||
name = "goo_format"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"common",
|
||||
"image",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -417,6 +515,12 @@ dependencies = [
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.12.1"
|
||||
@@ -1014,6 +1118,12 @@ dependencies = [
|
||||
"float-cmp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
@@ -1138,6 +1248,12 @@ version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "v_frame"
|
||||
version = "0.3.8"
|
||||
@@ -1231,6 +1347,79 @@ dependencies = [
|
||||
"safe_arch",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.13"
|
||||
|
@@ -1,70 +0,0 @@
|
||||
pub struct Serializer<'a> {
|
||||
buffer: &'a mut [u8],
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub struct SizedString<const SIZE: usize> {
|
||||
data: [u8; SIZE],
|
||||
}
|
||||
|
||||
impl<'a> Serializer<'a> {
|
||||
pub fn new(buffer: &'a mut [u8]) -> Self {
|
||||
Self { buffer, offset: 0 }
|
||||
}
|
||||
|
||||
pub fn write_bool(&mut self, data: bool) {
|
||||
self.write_u8(data as u8);
|
||||
}
|
||||
|
||||
pub fn write_u8(&mut self, data: u8) {
|
||||
self.buffer[self.offset] = data;
|
||||
self.offset += 1;
|
||||
}
|
||||
|
||||
pub fn write_u16(&mut self, data: u16) {
|
||||
self.buffer[self.offset..self.offset + 2].copy_from_slice(&data.to_be_bytes());
|
||||
self.offset += 2;
|
||||
}
|
||||
|
||||
pub fn write_u32(&mut self, data: u32) {
|
||||
self.buffer[self.offset..self.offset + 4].copy_from_slice(&data.to_be_bytes());
|
||||
self.offset += 4;
|
||||
}
|
||||
|
||||
pub fn write_u64(&mut self, data: u64) {
|
||||
self.buffer[self.offset..self.offset + 8].copy_from_slice(&data.to_be_bytes());
|
||||
self.offset += 8;
|
||||
}
|
||||
|
||||
pub fn write_f32(&mut self, data: f32) {
|
||||
self.buffer[self.offset..self.offset + 4].copy_from_slice(&data.to_be_bytes());
|
||||
self.offset += 4;
|
||||
}
|
||||
|
||||
pub fn write_bytes(&mut self, data: &[u8]) {
|
||||
self.buffer[self.offset..self.offset + data.len()].copy_from_slice(data);
|
||||
self.offset += data.len();
|
||||
}
|
||||
|
||||
pub fn write_sized_string<const SIZE: usize>(&mut self, data: &SizedString<SIZE>) {
|
||||
let len = data.data.len();
|
||||
self.buffer[self.offset..self.offset + len].copy_from_slice(&data.data);
|
||||
self.offset += len;
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> SizedString<SIZE> {
|
||||
pub const fn new(data: &[u8]) -> Self {
|
||||
debug_assert!(data.len() <= SIZE);
|
||||
|
||||
// kinda crazy this works in a const fn
|
||||
let mut arr = [0; SIZE];
|
||||
let mut i = 0;
|
||||
while i < SIZE && i < data.len() {
|
||||
arr[i] = data[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Self { data: arr }
|
||||
}
|
||||
}
|
79
common/src/serde/deserializer.rs
Normal file
79
common/src/serde/deserializer.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
use super::SizedString;
|
||||
|
||||
pub struct Deserializer<'a> {
|
||||
buffer: &'a [u8],
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<'a> Deserializer<'a> {
|
||||
pub fn new(data: &'a [u8]) -> Self {
|
||||
Self {
|
||||
buffer: data,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_bool(&mut self) -> bool {
|
||||
self.read_u8() != 0
|
||||
}
|
||||
|
||||
pub fn read_u8(&mut self) -> u8 {
|
||||
let value = self.buffer[self.offset];
|
||||
self.offset += 1;
|
||||
value
|
||||
}
|
||||
|
||||
pub fn read_u16(&mut self) -> u16 {
|
||||
let value = u16::from_be_bytes([self.buffer[self.offset], self.buffer[self.offset + 1]]);
|
||||
self.offset += 2;
|
||||
value
|
||||
}
|
||||
|
||||
pub fn read_u32(&mut self) -> u32 {
|
||||
let value = u32::from_be_bytes([
|
||||
self.buffer[self.offset],
|
||||
self.buffer[self.offset + 1],
|
||||
self.buffer[self.offset + 2],
|
||||
self.buffer[self.offset + 3],
|
||||
]);
|
||||
self.offset += 4;
|
||||
value
|
||||
}
|
||||
|
||||
pub fn read_u64(&mut self) -> u64 {
|
||||
let value = u64::from_be_bytes([
|
||||
self.buffer[self.offset],
|
||||
self.buffer[self.offset + 1],
|
||||
self.buffer[self.offset + 2],
|
||||
self.buffer[self.offset + 3],
|
||||
self.buffer[self.offset + 4],
|
||||
self.buffer[self.offset + 5],
|
||||
self.buffer[self.offset + 6],
|
||||
self.buffer[self.offset + 7],
|
||||
]);
|
||||
self.offset += 8;
|
||||
value
|
||||
}
|
||||
|
||||
pub fn read_f32(&mut self) -> f32 {
|
||||
let value = f32::from_be_bytes([
|
||||
self.buffer[self.offset],
|
||||
self.buffer[self.offset + 1],
|
||||
self.buffer[self.offset + 2],
|
||||
self.buffer[self.offset + 3],
|
||||
]);
|
||||
self.offset += 4;
|
||||
value
|
||||
}
|
||||
|
||||
pub fn read_bytes(&mut self, length: usize) -> &'a [u8] {
|
||||
let value = &self.buffer[self.offset..self.offset + length];
|
||||
self.offset += length;
|
||||
value
|
||||
}
|
||||
|
||||
pub fn read_sized_string<const SIZE: usize>(&mut self) -> SizedString<SIZE> {
|
||||
SizedString::new(self.read_bytes(SIZE))
|
||||
}
|
||||
}
|
7
common/src/serde/mod.rs
Normal file
7
common/src/serde/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
mod deserializer;
|
||||
mod serializer;
|
||||
mod types;
|
||||
|
||||
pub use deserializer::Deserializer;
|
||||
pub use serializer::Serializer;
|
||||
pub use types::SizedString;
|
113
common/src/serde/serializer.rs
Normal file
113
common/src/serde/serializer.rs
Normal file
@@ -0,0 +1,113 @@
|
||||
use super::SizedString;
|
||||
|
||||
pub trait Serializer {
|
||||
fn write_bool(&mut self, data: bool);
|
||||
fn write_u8(&mut self, data: u8);
|
||||
fn write_u16(&mut self, data: u16);
|
||||
fn write_u32(&mut self, data: u32);
|
||||
fn write_u64(&mut self, data: u64);
|
||||
fn write_f32(&mut self, data: f32);
|
||||
fn write_bytes(&mut self, data: &[u8]);
|
||||
fn write_sized_string<const SIZE: usize>(&mut self, data: &SizedString<SIZE>);
|
||||
}
|
||||
|
||||
pub struct SizedSerializer<'a> {
|
||||
buffer: &'a mut [u8],
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub struct DynamicSerializer {
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<'a> SizedSerializer<'a> {
|
||||
pub fn new(buffer: &'a mut [u8]) -> Self {
|
||||
Self { buffer, offset: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl DynamicSerializer {
|
||||
pub fn new() -> Self {
|
||||
Self { buffer: Vec::new() }
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> Vec<u8> {
|
||||
self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl Serializer for SizedSerializer<'_> {
|
||||
fn write_bool(&mut self, data: bool) {
|
||||
self.write_u8(data as u8);
|
||||
}
|
||||
|
||||
fn write_u8(&mut self, data: u8) {
|
||||
self.buffer[self.offset] = data;
|
||||
self.offset += 1;
|
||||
}
|
||||
|
||||
fn write_u16(&mut self, data: u16) {
|
||||
self.buffer[self.offset..self.offset + 2].copy_from_slice(&data.to_be_bytes());
|
||||
self.offset += 2;
|
||||
}
|
||||
|
||||
fn write_u32(&mut self, data: u32) {
|
||||
self.buffer[self.offset..self.offset + 4].copy_from_slice(&data.to_be_bytes());
|
||||
self.offset += 4;
|
||||
}
|
||||
|
||||
fn write_u64(&mut self, data: u64) {
|
||||
self.buffer[self.offset..self.offset + 8].copy_from_slice(&data.to_be_bytes());
|
||||
self.offset += 8;
|
||||
}
|
||||
|
||||
fn write_f32(&mut self, data: f32) {
|
||||
self.buffer[self.offset..self.offset + 4].copy_from_slice(&data.to_be_bytes());
|
||||
self.offset += 4;
|
||||
}
|
||||
|
||||
fn write_bytes(&mut self, data: &[u8]) {
|
||||
self.buffer[self.offset..self.offset + data.len()].copy_from_slice(data);
|
||||
self.offset += data.len();
|
||||
}
|
||||
|
||||
fn write_sized_string<const SIZE: usize>(&mut self, data: &SizedString<SIZE>) {
|
||||
let len = data.data.len();
|
||||
self.buffer[self.offset..self.offset + len].copy_from_slice(&data.data);
|
||||
self.offset += len;
|
||||
}
|
||||
}
|
||||
|
||||
impl Serializer for DynamicSerializer {
|
||||
fn write_bool(&mut self, data: bool) {
|
||||
self.write_u8(data as u8);
|
||||
}
|
||||
|
||||
fn write_u8(&mut self, data: u8) {
|
||||
self.buffer.push(data);
|
||||
}
|
||||
|
||||
fn write_u16(&mut self, data: u16) {
|
||||
self.buffer.extend_from_slice(&data.to_be_bytes());
|
||||
}
|
||||
|
||||
fn write_u32(&mut self, data: u32) {
|
||||
self.buffer.extend_from_slice(&data.to_be_bytes());
|
||||
}
|
||||
|
||||
fn write_u64(&mut self, data: u64) {
|
||||
self.buffer.extend_from_slice(&data.to_be_bytes());
|
||||
}
|
||||
|
||||
fn write_f32(&mut self, data: f32) {
|
||||
self.buffer.extend_from_slice(&data.to_be_bytes());
|
||||
}
|
||||
|
||||
fn write_bytes(&mut self, data: &[u8]) {
|
||||
self.buffer.extend_from_slice(data);
|
||||
}
|
||||
|
||||
fn write_sized_string<const SIZE: usize>(&mut self, data: &SizedString<SIZE>) {
|
||||
self.buffer.extend_from_slice(&data.data);
|
||||
}
|
||||
}
|
42
common/src/serde/types.rs
Normal file
42
common/src/serde/types.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use std::fmt::{self, Debug, Display};
|
||||
|
||||
pub struct SizedString<const SIZE: usize> {
|
||||
pub(crate) data: [u8; SIZE],
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> SizedString<SIZE> {
|
||||
pub const fn new_full(data: [u8; SIZE]) -> Self {
|
||||
Self { data }
|
||||
}
|
||||
|
||||
pub const fn new(data: &[u8]) -> Self {
|
||||
debug_assert!(data.len() <= SIZE);
|
||||
|
||||
// kinda crazy this works in a const fn
|
||||
let mut arr = [0; SIZE];
|
||||
let mut i = 0;
|
||||
while i < SIZE && i < data.len() {
|
||||
arr[i] = data[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Self { data: arr }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SizedString<32> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let null = self.data.iter().position(|&x| x == 0).unwrap_or(32);
|
||||
f.write_str(&String::from_utf8_lossy(&self.data[..null]))
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize> Debug for SizedString<SIZE> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let null = self.data.iter().position(|&x| x == 0).unwrap_or(SIZE);
|
||||
f.write_fmt(format_args!(
|
||||
"\"{}\"",
|
||||
String::from_utf8_lossy(&self.data[..null])
|
||||
))
|
||||
}
|
||||
}
|
@@ -6,4 +6,8 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
clap = { version = "4.5.7", features = ["derive"] }
|
||||
|
||||
common = { path = "../common" }
|
||||
image = "0.25.1"
|
||||
|
94
goo_format/src/default.rs
Normal file
94
goo_format/src/default.rs
Normal file
@@ -0,0 +1,94 @@
|
||||
use common::serde::SizedString;
|
||||
|
||||
use crate::{HeaderInfo, LayerContent, PreviewImage};
|
||||
|
||||
impl Default for HeaderInfo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: SizedString::new(b"V3.0"),
|
||||
software_info: SizedString::new(b"sla_slicer by Connor Slade"),
|
||||
software_version: SizedString::new(b"0.1.0"),
|
||||
file_time: SizedString::new(b"2024-06-14 08:10:14"),
|
||||
printer_name: SizedString::new(b"standard"),
|
||||
printer_type: SizedString::new(b"Default"),
|
||||
profile_name: SizedString::new(b"New Script"),
|
||||
anti_aliasing_level: 8,
|
||||
grey_level: 0,
|
||||
blur_level: 0,
|
||||
small_preview: PreviewImage::empty(),
|
||||
big_preview: PreviewImage::empty(),
|
||||
layer_count: 171,
|
||||
x_resolution: 11520,
|
||||
y_resolution: 5102,
|
||||
x_mirror: false,
|
||||
y_mirror: false,
|
||||
x_size: 218.88,
|
||||
y_size: 122.88,
|
||||
z_size: 260.0,
|
||||
layer_thickness: 0.05,
|
||||
exposure_time: 3.0,
|
||||
exposure_delay_mode: true,
|
||||
turn_off_time: 0.0,
|
||||
bottom_before_lift_time: 0.0,
|
||||
bottom_after_lift_time: 0.0,
|
||||
bottom_after_retract_time: 0.0,
|
||||
before_lift_time: 0.0,
|
||||
after_lift_time: 0.0,
|
||||
after_retract_time: 0.0,
|
||||
bottom_exposure_time: 50.0,
|
||||
bottom_layers: 8,
|
||||
bottom_lift_distance: 5.0,
|
||||
bottom_lift_speed: 65.0,
|
||||
lift_distance: 5.0,
|
||||
lift_speed: 65.0,
|
||||
bottom_retract_distance: 5.0,
|
||||
bottom_retract_speed: 150.0,
|
||||
retract_distance: 5.0,
|
||||
retract_speed: 0.0,
|
||||
bottom_second_lift_distance: 0.0,
|
||||
bottom_second_lift_speed: 0.0,
|
||||
second_lift_distance: 0.0,
|
||||
second_lift_speed: 0.0,
|
||||
bottom_second_retract_distance: 0.0,
|
||||
bottom_second_retract_speed: 0.0,
|
||||
second_retract_distance: 0.0,
|
||||
second_retract_speed: 0.0,
|
||||
bottom_light_pwm: 255,
|
||||
light_pwm: 255,
|
||||
advance_mode: false,
|
||||
printing_time: 2659,
|
||||
total_volume: 526.507,
|
||||
total_weight: 0.684,
|
||||
total_price: 0.0,
|
||||
price_unit: SizedString::new(b"$"),
|
||||
grey_scale_level: true,
|
||||
transition_layers: 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LayerContent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pause_flag: 0,
|
||||
pause_position_z: 200.0,
|
||||
layer_position_z: 0.05,
|
||||
layer_exposure_time: 50.0,
|
||||
layer_off_time: 0.0,
|
||||
before_lift_time: 0.0,
|
||||
after_lift_time: 0.0,
|
||||
after_retract_time: 0.0,
|
||||
lift_distance: 5.0,
|
||||
lift_speed: 65.0,
|
||||
second_lift_distance: 0.0,
|
||||
second_lift_speed: 0.0,
|
||||
retract_distance: 5.0,
|
||||
retract_speed: 150.0,
|
||||
second_retract_distance: 0.0,
|
||||
second_retract_speed: 0.0,
|
||||
light_pwm: 255,
|
||||
data: Vec::new(),
|
||||
checksum: 0,
|
||||
}
|
||||
}
|
||||
}
|
185
goo_format/src/encoded_layer.rs
Normal file
185
goo_format/src/encoded_layer.rs
Normal file
@@ -0,0 +1,185 @@
|
||||
use crate::layer_content::calculate_checksum;
|
||||
|
||||
pub struct LayerEncoder {
|
||||
data: Vec<u8>,
|
||||
last_value: u8,
|
||||
}
|
||||
|
||||
pub struct LayerDecoder<'a> {
|
||||
data: &'a [u8],
|
||||
color: u8,
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
pub struct Run {
|
||||
pub length: u64,
|
||||
pub value: u8,
|
||||
}
|
||||
|
||||
impl LayerEncoder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: Vec::new(),
|
||||
last_value: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_run(&mut self, length: u64, value: u8) {
|
||||
// byte 0: aabbcccc
|
||||
// a => 0: full black, 1: full white, 2: small diff, 3: large diff
|
||||
// b => 0: 4 bit length, 1: 12 bit value, 2: 20 bit value, 3: 28 bit value
|
||||
// c => the first 4 bits of the value
|
||||
// byte 1-3: optional, the rest of the value
|
||||
|
||||
let diff = value as i16 - self.last_value as i16;
|
||||
let byte_0: u8 = match value {
|
||||
// Full black and full white are always encoded as is
|
||||
0x00 => 0b00,
|
||||
0xFF => 0b11,
|
||||
_ if !self.data.is_empty() && diff.abs() <= 15 => {
|
||||
// 0babcccc
|
||||
// a => 0: add diff, 1: sub diff
|
||||
// b => 0: length of 1, 1: length is next byte
|
||||
// c => the diff
|
||||
|
||||
if length > 255 {
|
||||
self.add_run(255, value);
|
||||
self.add_run(length - 255, value);
|
||||
return;
|
||||
}
|
||||
|
||||
let byte_0 = (0b10 << 6)
|
||||
| (((diff > 0) as u8) << 5)
|
||||
| (((length != 1) as u8) << 4)
|
||||
| (diff.abs() as u8);
|
||||
self.data.push(byte_0);
|
||||
|
||||
if length != 1 {
|
||||
self.data.push(length as u8);
|
||||
}
|
||||
|
||||
self.last_value = value;
|
||||
return;
|
||||
}
|
||||
_ => 0b01,
|
||||
} << 6;
|
||||
|
||||
let chunk_length_size = match length {
|
||||
0x0000000..=0x000000F => 0b00,
|
||||
0x0000010..=0x0000FFF => 0b01,
|
||||
0x0001000..=0x00FFFFF => 0b10,
|
||||
0x0100000..=0xFFFFFFF => 0b11,
|
||||
_ => {
|
||||
self.add_run(0xFFFFFFF, value);
|
||||
self.add_run(length - 0xFFFFFFF, value);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
self.data
|
||||
.push(byte_0 | (chunk_length_size << 4) | (length as u8 & 0x0F));
|
||||
match chunk_length_size {
|
||||
1 => self.data.extend_from_slice(&[(length >> 4) as u8]),
|
||||
2 => self
|
||||
.data
|
||||
.extend_from_slice(&[(length >> 12) as u8, (length >> 4) as u8]),
|
||||
3 => self.data.extend_from_slice(&[
|
||||
(length >> 20) as u8,
|
||||
(length >> 12) as u8,
|
||||
(length >> 4) as u8,
|
||||
]),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.last_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LayerDecoder<'a> {
|
||||
pub fn new(data: &'a [u8]) -> Self {
|
||||
Self {
|
||||
data,
|
||||
color: 0,
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn checksum(&self) -> u8 {
|
||||
calculate_checksum(&self.data)
|
||||
}
|
||||
}
|
||||
|
||||
impl Iterator for LayerDecoder<'_> {
|
||||
type Item = Run;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.offset >= self.data.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut length = 0;
|
||||
let head = self.data[self.offset];
|
||||
|
||||
// 0b00 -> All 0x00 pixels
|
||||
// 0b01 -> Gray between 0x01 to 0xFE (byte 1)
|
||||
// 0b10 -> Diff value from the previous pixel
|
||||
// 0b11 -> All 0xFF pixels
|
||||
let chunk_type = head >> 6;
|
||||
let chunk_length_size = head >> 4 & 0x03;
|
||||
match chunk_type {
|
||||
0b00 => self.color = 0,
|
||||
0b01 => {
|
||||
self.offset += 1;
|
||||
self.color = self.data[self.offset]
|
||||
}
|
||||
0b10 => {
|
||||
let diff_type = head >> 4 & 0x03;
|
||||
let diff_value = head & 0x0F;
|
||||
if diff_type & 0b01 == 0 {
|
||||
length = 1;
|
||||
} else {
|
||||
self.offset += 1;
|
||||
length = self.data[self.offset] as u64;
|
||||
}
|
||||
if diff_type & 0b10 == 0 {
|
||||
self.color += diff_value;
|
||||
} else {
|
||||
self.color -= diff_value;
|
||||
}
|
||||
}
|
||||
0b11 => self.color = 0xFF,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if chunk_type != 0b10 {
|
||||
let base = (head & 0x0F) as u64;
|
||||
match chunk_length_size {
|
||||
0b00 => length = base,
|
||||
0b01 => {
|
||||
length = base + ((self.data[self.offset + 1] as u64) << 4);
|
||||
self.offset += 1;
|
||||
}
|
||||
0b10 => {
|
||||
length = base
|
||||
+ ((self.data[self.offset + 1] as u64) << 12)
|
||||
+ ((self.data[self.offset + 2] as u64) << 4);
|
||||
self.offset += 2;
|
||||
}
|
||||
0b11 => {
|
||||
length = base
|
||||
+ ((self.data[self.offset + 1] as u64) << 20)
|
||||
+ ((self.data[self.offset + 2] as u64) << 12)
|
||||
+ ((self.data[self.offset + 3] as u64) << 4);
|
||||
self.offset += 3;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
self.offset += 1;
|
||||
|
||||
Some(Run {
|
||||
length,
|
||||
value: self.color,
|
||||
})
|
||||
}
|
||||
}
|
44
goo_format/src/file.rs
Normal file
44
goo_format/src/file.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use anyhow::{ensure, Result};
|
||||
|
||||
use common::serde::{Deserializer, Serializer};
|
||||
|
||||
use crate::{HeaderInfo, LayerContent};
|
||||
|
||||
const ENDING_STRING: &[u8] = &[
|
||||
0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x44, 0x4C, 0x50, 0x00,
|
||||
];
|
||||
|
||||
pub struct File {
|
||||
pub header: HeaderInfo,
|
||||
pub layers: Vec<LayerContent>,
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn new(header: HeaderInfo, layers: Vec<LayerContent>) -> Self {
|
||||
Self { header, layers }
|
||||
}
|
||||
}
|
||||
|
||||
impl File {
|
||||
pub fn serialize<T: Serializer>(&self, ser: &mut T) {
|
||||
self.header.serialize(ser);
|
||||
for layer in &self.layers {
|
||||
layer.serialize(ser);
|
||||
}
|
||||
ser.write_bytes(ENDING_STRING);
|
||||
}
|
||||
|
||||
pub fn deserialize(buf: &[u8]) -> Result<Self> {
|
||||
let mut des = Deserializer::new(buf);
|
||||
|
||||
let header = HeaderInfo::deserialize(&buf[0..HeaderInfo::SIZE])?;
|
||||
let mut layers = Vec::with_capacity(header.layer_count as usize);
|
||||
|
||||
for _ in 0..header.layer_count {
|
||||
layers.push(LayerContent::deserialize(&buf[HeaderInfo::SIZE..])?);
|
||||
}
|
||||
|
||||
ensure!(des.read_bytes(ENDING_STRING.len()) == ENDING_STRING);
|
||||
Ok(Self { header, layers })
|
||||
}
|
||||
}
|
340
goo_format/src/header_info.rs
Normal file
340
goo_format/src/header_info.rs
Normal file
@@ -0,0 +1,340 @@
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
use anyhow::{ensure, Result};
|
||||
|
||||
use common::serde::{Deserializer, Serializer, SizedString};
|
||||
|
||||
use crate::PreviewImage;
|
||||
|
||||
pub struct HeaderInfo {
|
||||
pub version: SizedString<4>,
|
||||
pub software_info: SizedString<32>,
|
||||
pub software_version: SizedString<24>,
|
||||
pub file_time: SizedString<24>,
|
||||
pub printer_name: SizedString<32>,
|
||||
pub printer_type: SizedString<32>,
|
||||
pub profile_name: SizedString<32>,
|
||||
pub anti_aliasing_level: u16,
|
||||
pub grey_level: u16,
|
||||
pub blur_level: u16,
|
||||
pub small_preview: PreviewImage<116, 116>,
|
||||
pub big_preview: PreviewImage<290, 290>,
|
||||
pub layer_count: u32,
|
||||
pub x_resolution: u16,
|
||||
pub y_resolution: u16,
|
||||
pub x_mirror: bool,
|
||||
pub y_mirror: bool,
|
||||
pub x_size: f32,
|
||||
pub y_size: f32,
|
||||
pub z_size: f32,
|
||||
pub layer_thickness: f32,
|
||||
pub exposure_time: f32,
|
||||
pub exposure_delay_mode: bool,
|
||||
pub turn_off_time: f32,
|
||||
pub bottom_before_lift_time: f32,
|
||||
pub bottom_after_lift_time: f32,
|
||||
pub bottom_after_retract_time: f32,
|
||||
pub before_lift_time: f32,
|
||||
pub after_lift_time: f32,
|
||||
pub after_retract_time: f32,
|
||||
pub bottom_exposure_time: f32,
|
||||
pub bottom_layers: u32,
|
||||
pub bottom_lift_distance: f32,
|
||||
pub bottom_lift_speed: f32,
|
||||
pub lift_distance: f32,
|
||||
pub lift_speed: f32,
|
||||
pub bottom_retract_distance: f32,
|
||||
pub bottom_retract_speed: f32,
|
||||
pub retract_distance: f32,
|
||||
pub retract_speed: f32,
|
||||
pub bottom_second_lift_distance: f32,
|
||||
pub bottom_second_lift_speed: f32,
|
||||
pub second_lift_distance: f32,
|
||||
pub second_lift_speed: f32,
|
||||
pub bottom_second_retract_distance: f32,
|
||||
pub bottom_second_retract_speed: f32,
|
||||
pub second_retract_distance: f32,
|
||||
pub second_retract_speed: f32,
|
||||
pub bottom_light_pwm: u16,
|
||||
pub light_pwm: u16,
|
||||
pub advance_mode: bool,
|
||||
pub printing_time: u32,
|
||||
pub total_volume: f32,
|
||||
pub total_weight: f32,
|
||||
pub total_price: f32,
|
||||
pub price_unit: SizedString<8>,
|
||||
pub grey_scale_level: bool,
|
||||
pub transition_layers: u16,
|
||||
}
|
||||
|
||||
impl HeaderInfo {
|
||||
pub const SIZE: usize = 0x2FB95;
|
||||
}
|
||||
|
||||
// this is fine
|
||||
impl HeaderInfo {
|
||||
pub fn serialize<T: Serializer>(&self, ser: &mut T) {
|
||||
ser.write_sized_string(&self.version);
|
||||
ser.write_bytes(&[0x07, 0x00, 0x00, 0x00, 0x44, 0x4C, 0x50, 0x00]);
|
||||
ser.write_sized_string(&self.software_info);
|
||||
ser.write_sized_string(&self.software_version);
|
||||
ser.write_sized_string(&self.file_time);
|
||||
ser.write_sized_string(&self.printer_name);
|
||||
ser.write_sized_string(&self.printer_type);
|
||||
ser.write_sized_string(&self.profile_name);
|
||||
ser.write_u16(self.anti_aliasing_level);
|
||||
ser.write_u16(self.grey_level);
|
||||
ser.write_u16(self.blur_level);
|
||||
self.small_preview.serializes(ser);
|
||||
ser.write_bytes(&[0xd, 0xa]);
|
||||
self.big_preview.serializes(ser);
|
||||
ser.write_bytes(&[0xd, 0xa]);
|
||||
ser.write_u32(self.layer_count);
|
||||
ser.write_u16(self.x_resolution);
|
||||
ser.write_u16(self.y_resolution);
|
||||
ser.write_bool(self.x_mirror);
|
||||
ser.write_bool(self.y_mirror);
|
||||
ser.write_f32(self.x_size);
|
||||
ser.write_f32(self.y_size);
|
||||
ser.write_f32(self.z_size);
|
||||
ser.write_f32(self.layer_thickness);
|
||||
ser.write_f32(self.exposure_time);
|
||||
ser.write_bool(self.exposure_delay_mode);
|
||||
ser.write_f32(self.turn_off_time);
|
||||
ser.write_f32(self.bottom_before_lift_time);
|
||||
ser.write_f32(self.bottom_after_lift_time);
|
||||
ser.write_f32(self.bottom_after_retract_time);
|
||||
ser.write_f32(self.before_lift_time);
|
||||
ser.write_f32(self.after_lift_time);
|
||||
ser.write_f32(self.after_retract_time);
|
||||
ser.write_f32(self.bottom_exposure_time);
|
||||
ser.write_u32(self.bottom_layers);
|
||||
ser.write_f32(self.bottom_lift_distance);
|
||||
ser.write_f32(self.bottom_lift_speed);
|
||||
ser.write_f32(self.lift_distance);
|
||||
ser.write_f32(self.lift_speed);
|
||||
ser.write_f32(self.bottom_retract_distance);
|
||||
ser.write_f32(self.bottom_retract_speed);
|
||||
ser.write_f32(self.retract_distance);
|
||||
ser.write_f32(self.retract_speed);
|
||||
ser.write_f32(self.bottom_second_lift_distance);
|
||||
ser.write_f32(self.bottom_second_lift_speed);
|
||||
ser.write_f32(self.second_lift_distance);
|
||||
ser.write_f32(self.second_lift_speed);
|
||||
ser.write_f32(self.bottom_second_retract_distance);
|
||||
ser.write_f32(self.bottom_second_retract_speed);
|
||||
ser.write_f32(self.second_retract_distance);
|
||||
ser.write_f32(self.second_retract_speed);
|
||||
ser.write_u16(self.bottom_light_pwm);
|
||||
ser.write_u16(self.light_pwm);
|
||||
ser.write_bool(self.advance_mode);
|
||||
ser.write_u32(self.printing_time);
|
||||
ser.write_f32(self.total_volume);
|
||||
ser.write_f32(self.total_weight);
|
||||
ser.write_f32(self.total_price);
|
||||
ser.write_sized_string(&self.price_unit);
|
||||
ser.write_u32(Self::SIZE as u32);
|
||||
ser.write_bool(self.grey_scale_level);
|
||||
ser.write_u16(self.transition_layers);
|
||||
}
|
||||
|
||||
pub fn deserialize(buf: &[u8]) -> Result<Self> {
|
||||
let mut des = Deserializer::new(buf);
|
||||
|
||||
let version = des.read_sized_string();
|
||||
ensure!(des.read_bytes(8) == [0x07, 0x00, 0x00, 0x00, 0x44, 0x4C, 0x50, 0x00]);
|
||||
let software_info = des.read_sized_string();
|
||||
let software_version = des.read_sized_string();
|
||||
let file_time = des.read_sized_string();
|
||||
let printer_name = des.read_sized_string();
|
||||
let printer_type = des.read_sized_string();
|
||||
let profile_name = des.read_sized_string();
|
||||
let anti_aliasing_level = des.read_u16();
|
||||
let grey_level = des.read_u16();
|
||||
let blur_level = des.read_u16();
|
||||
let small_preview = PreviewImage::deserializes(&mut des);
|
||||
ensure!(des.read_bytes(2) == [0xd, 0xa]);
|
||||
let big_preview = PreviewImage::deserializes(&mut des);
|
||||
ensure!(des.read_bytes(2) == [0xd, 0xa]);
|
||||
let layer_count = des.read_u32();
|
||||
let x_resolution = des.read_u16();
|
||||
let y_resolution = des.read_u16();
|
||||
let x_mirror = des.read_bool();
|
||||
let y_mirror = des.read_bool();
|
||||
let x_size = des.read_f32();
|
||||
let y_size = des.read_f32();
|
||||
let z_size = des.read_f32();
|
||||
let layer_thickness = des.read_f32();
|
||||
let exposure_time = des.read_f32();
|
||||
let exposure_delay_mode = des.read_bool();
|
||||
let turn_off_time = des.read_f32();
|
||||
let bottom_before_lift_time = des.read_f32();
|
||||
let bottom_after_lift_time = des.read_f32();
|
||||
let bottom_after_retract_time = des.read_f32();
|
||||
let before_lift_time = des.read_f32();
|
||||
let after_lift_time = des.read_f32();
|
||||
let after_retract_time = des.read_f32();
|
||||
let bottom_exposure_time = des.read_f32();
|
||||
let bottom_layers = des.read_u32();
|
||||
let bottom_lift_distance = des.read_f32();
|
||||
let bottom_lift_speed = des.read_f32();
|
||||
let lift_distance = des.read_f32();
|
||||
let lift_speed = des.read_f32();
|
||||
let bottom_retract_distance = des.read_f32();
|
||||
let bottom_retract_speed = des.read_f32();
|
||||
let retract_distance = des.read_f32();
|
||||
let retract_speed = des.read_f32();
|
||||
let bottom_second_lift_distance = des.read_f32();
|
||||
let bottom_second_lift_speed = des.read_f32();
|
||||
let second_lift_distance = des.read_f32();
|
||||
let second_lift_speed = des.read_f32();
|
||||
let bottom_second_retract_distance = des.read_f32();
|
||||
let bottom_second_retract_speed = des.read_f32();
|
||||
let second_retract_distance = des.read_f32();
|
||||
let second_retract_speed = des.read_f32();
|
||||
let bottom_light_pwm = des.read_u16();
|
||||
let light_pwm = des.read_u16();
|
||||
let advance_mode = des.read_bool();
|
||||
let printing_time = des.read_u32();
|
||||
let total_volume = des.read_f32();
|
||||
let total_weight = des.read_f32();
|
||||
let total_price = des.read_f32();
|
||||
let price_unit = des.read_sized_string();
|
||||
ensure!(des.read_u32() == Self::SIZE as u32);
|
||||
let grey_scale_level = des.read_bool();
|
||||
let transition_layers = des.read_u16();
|
||||
|
||||
Ok(Self {
|
||||
version,
|
||||
software_info,
|
||||
software_version,
|
||||
file_time,
|
||||
printer_name,
|
||||
printer_type,
|
||||
profile_name,
|
||||
anti_aliasing_level,
|
||||
grey_level,
|
||||
blur_level,
|
||||
small_preview,
|
||||
big_preview,
|
||||
layer_count,
|
||||
x_resolution,
|
||||
y_resolution,
|
||||
x_mirror,
|
||||
y_mirror,
|
||||
x_size,
|
||||
y_size,
|
||||
z_size,
|
||||
layer_thickness,
|
||||
exposure_time,
|
||||
exposure_delay_mode,
|
||||
turn_off_time,
|
||||
bottom_before_lift_time,
|
||||
bottom_after_lift_time,
|
||||
bottom_after_retract_time,
|
||||
before_lift_time,
|
||||
after_lift_time,
|
||||
after_retract_time,
|
||||
bottom_exposure_time,
|
||||
bottom_layers,
|
||||
bottom_lift_distance,
|
||||
bottom_lift_speed,
|
||||
lift_distance,
|
||||
lift_speed,
|
||||
bottom_retract_distance,
|
||||
bottom_retract_speed,
|
||||
retract_distance,
|
||||
retract_speed,
|
||||
bottom_second_lift_distance,
|
||||
bottom_second_lift_speed,
|
||||
second_lift_distance,
|
||||
second_lift_speed,
|
||||
bottom_second_retract_distance,
|
||||
bottom_second_retract_speed,
|
||||
second_retract_distance,
|
||||
second_retract_speed,
|
||||
bottom_light_pwm,
|
||||
light_pwm,
|
||||
advance_mode,
|
||||
printing_time,
|
||||
total_volume,
|
||||
total_weight,
|
||||
total_price,
|
||||
price_unit,
|
||||
grey_scale_level,
|
||||
transition_layers,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for HeaderInfo {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("HeaderInfo")
|
||||
.field("version", &self.version)
|
||||
.field("software_info", &self.software_info)
|
||||
.field("software_version", &self.software_version)
|
||||
.field("file_time", &self.file_time)
|
||||
.field("printer_name", &self.printer_name)
|
||||
.field("printer_type", &self.printer_type)
|
||||
.field("profile_name", &self.profile_name)
|
||||
.field("anti_aliasing_level", &self.anti_aliasing_level)
|
||||
.field("grey_level", &self.grey_level)
|
||||
.field("blur_level", &self.blur_level)
|
||||
.field("layer_count", &self.layer_count)
|
||||
.field("x_resolution", &self.x_resolution)
|
||||
.field("y_resolution", &self.y_resolution)
|
||||
.field("x_mirror", &self.x_mirror)
|
||||
.field("y_mirror", &self.y_mirror)
|
||||
.field("x_size", &self.x_size)
|
||||
.field("y_size", &self.y_size)
|
||||
.field("z_size", &self.z_size)
|
||||
.field("layer_thickness", &self.layer_thickness)
|
||||
.field("exposure_time", &self.exposure_time)
|
||||
.field("exposure_delay_mode", &self.exposure_delay_mode)
|
||||
.field("turn_off_time", &self.turn_off_time)
|
||||
.field("bottom_before_lift_time", &self.bottom_before_lift_time)
|
||||
.field("bottom_after_lift_time", &self.bottom_after_lift_time)
|
||||
.field("bottom_after_retract_time", &self.bottom_after_retract_time)
|
||||
.field("before_lift_time", &self.before_lift_time)
|
||||
.field("after_lift_time", &self.after_lift_time)
|
||||
.field("after_retract_time", &self.after_retract_time)
|
||||
.field("bottom_exposure_time", &self.bottom_exposure_time)
|
||||
.field("bottom_layers", &self.bottom_layers)
|
||||
.field("bottom_lift_distance", &self.bottom_lift_distance)
|
||||
.field("bottom_lift_speed", &self.bottom_lift_speed)
|
||||
.field("lift_distance", &self.lift_distance)
|
||||
.field("lift_speed", &self.lift_speed)
|
||||
.field("bottom_retract_distance", &self.bottom_retract_distance)
|
||||
.field("bottom_retract_speed", &self.bottom_retract_speed)
|
||||
.field("retract_distance", &self.retract_distance)
|
||||
.field("retract_speed", &self.retract_speed)
|
||||
.field(
|
||||
"bottom_second_lift_distance",
|
||||
&self.bottom_second_lift_distance,
|
||||
)
|
||||
.field("bottom_second_lift_speed", &self.bottom_second_lift_speed)
|
||||
.field("second_lift_distance", &self.second_lift_distance)
|
||||
.field("second_lift_speed", &self.second_lift_speed)
|
||||
.field(
|
||||
"bottom_second_retract_distance",
|
||||
&self.bottom_second_retract_distance,
|
||||
)
|
||||
.field(
|
||||
"bottom_second_retract_speed",
|
||||
&self.bottom_second_retract_speed,
|
||||
)
|
||||
.field("second_retract_distance", &self.second_retract_distance)
|
||||
.field("second_retract_speed", &self.second_retract_speed)
|
||||
.field("bottom_light_pwm", &self.bottom_light_pwm)
|
||||
.field("light_pwm", &self.light_pwm)
|
||||
.field("advance_mode", &self.advance_mode)
|
||||
.field("printing_time", &self.printing_time)
|
||||
.field("total_volume", &self.total_volume)
|
||||
.field("total_weight", &self.total_weight)
|
||||
.field("total_price", &self.total_price)
|
||||
.field("price_unit", &self.price_unit)
|
||||
.field("grey_scale_level", &self.grey_scale_level)
|
||||
.field("transition_layers", &self.transition_layers)
|
||||
.finish()
|
||||
}
|
||||
}
|
109
goo_format/src/layer_content.rs
Normal file
109
goo_format/src/layer_content.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
use anyhow::{bail, ensure, Result};
|
||||
|
||||
use common::serde::{Deserializer, Serializer};
|
||||
|
||||
pub struct LayerContent {
|
||||
pub pause_flag: u16,
|
||||
pub pause_position_z: f32,
|
||||
pub layer_position_z: f32,
|
||||
pub layer_exposure_time: f32,
|
||||
pub layer_off_time: f32,
|
||||
pub before_lift_time: f32,
|
||||
pub after_lift_time: f32,
|
||||
pub after_retract_time: f32,
|
||||
pub lift_distance: f32,
|
||||
pub lift_speed: f32,
|
||||
pub second_lift_distance: f32,
|
||||
pub second_lift_speed: f32,
|
||||
pub retract_distance: f32,
|
||||
pub retract_speed: f32,
|
||||
pub second_retract_distance: f32,
|
||||
pub second_retract_speed: f32,
|
||||
pub light_pwm: u16,
|
||||
pub data: Vec<u8>,
|
||||
pub checksum: u8,
|
||||
}
|
||||
|
||||
impl LayerContent {
|
||||
pub fn serialize<T: Serializer>(&self, ser: &mut T) {
|
||||
ser.write_u16(self.pause_flag);
|
||||
ser.write_f32(self.pause_position_z);
|
||||
ser.write_f32(self.layer_position_z);
|
||||
ser.write_f32(self.layer_exposure_time);
|
||||
ser.write_f32(self.layer_off_time);
|
||||
ser.write_f32(self.before_lift_time);
|
||||
ser.write_f32(self.after_lift_time);
|
||||
ser.write_f32(self.after_retract_time);
|
||||
ser.write_f32(self.lift_distance);
|
||||
ser.write_f32(self.lift_speed);
|
||||
ser.write_f32(self.second_lift_distance);
|
||||
ser.write_f32(self.second_lift_speed);
|
||||
ser.write_f32(self.retract_distance);
|
||||
ser.write_f32(self.retract_speed);
|
||||
ser.write_f32(self.second_retract_distance);
|
||||
ser.write_f32(self.second_retract_speed);
|
||||
ser.write_u16(self.light_pwm);
|
||||
ser.write_u32(self.data.len() as u32 + 2);
|
||||
ser.write_bytes(&[0x55]);
|
||||
ser.write_bytes(&self.data);
|
||||
ser.write_u8(calculate_checksum(&self.data));
|
||||
ser.write_bytes(&[0xd, 0xa]);
|
||||
}
|
||||
|
||||
pub fn deserialize(buf: &[u8]) -> Result<Self> {
|
||||
let mut des = Deserializer::new(buf);
|
||||
|
||||
let pause_flag = des.read_u16();
|
||||
let pause_position_z = des.read_f32();
|
||||
let layer_position_z = des.read_f32();
|
||||
let layer_exposure_time = des.read_f32();
|
||||
let layer_off_time = des.read_f32();
|
||||
let before_lift_time = des.read_f32();
|
||||
let after_lift_time = des.read_f32();
|
||||
let after_retract_time = des.read_f32();
|
||||
let lift_distance = des.read_f32();
|
||||
let lift_speed = des.read_f32();
|
||||
let second_lift_distance = des.read_f32();
|
||||
let second_lift_speed = des.read_f32();
|
||||
let retract_distance = des.read_f32();
|
||||
let retract_speed = des.read_f32();
|
||||
let second_retract_distance = des.read_f32();
|
||||
let second_retract_speed = des.read_f32();
|
||||
let light_pwm = des.read_u16();
|
||||
let data_len = des.read_u32() as usize - 2;
|
||||
ensure!(des.read_u8() == 0x55);
|
||||
let data = des.read_bytes(data_len);
|
||||
let checksum = des.read_u8();
|
||||
ensure!(des.read_bytes(2) == [0xd, 0xa]);
|
||||
|
||||
Ok(Self {
|
||||
pause_flag,
|
||||
pause_position_z,
|
||||
layer_position_z,
|
||||
layer_exposure_time,
|
||||
layer_off_time,
|
||||
before_lift_time,
|
||||
after_lift_time,
|
||||
after_retract_time,
|
||||
lift_distance,
|
||||
lift_speed,
|
||||
second_lift_distance,
|
||||
second_lift_speed,
|
||||
retract_distance,
|
||||
retract_speed,
|
||||
second_retract_distance,
|
||||
second_retract_speed,
|
||||
light_pwm,
|
||||
data: data.to_vec(), // ehhh its fiiiine (its not fine)
|
||||
checksum,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_checksum(data: &[u8]) -> u8 {
|
||||
let mut out = 0u8;
|
||||
for &byte in data {
|
||||
out = out.wrapping_add(byte);
|
||||
}
|
||||
!out
|
||||
}
|
@@ -1,383 +1,12 @@
|
||||
use common::serde::{Serializer, SizedString};
|
||||
mod default;
|
||||
mod encoded_layer;
|
||||
mod file;
|
||||
mod header_info;
|
||||
mod layer_content;
|
||||
mod preview_image;
|
||||
|
||||
pub struct HeaderInfo {
|
||||
pub version: SizedString<4>,
|
||||
pub software_info: SizedString<32>,
|
||||
pub software_version: SizedString<24>,
|
||||
pub file_time: SizedString<24>,
|
||||
pub printer_name: SizedString<32>,
|
||||
pub printer_type: SizedString<32>,
|
||||
pub profile_name: SizedString<32>,
|
||||
pub anti_aliasing_level: u16,
|
||||
pub grey_level: u16,
|
||||
pub blur_level: u16,
|
||||
pub small_preview: PreviewImage<116, 116>,
|
||||
pub big_preview: PreviewImage<290, 290>,
|
||||
pub layer_count: u32,
|
||||
pub x_resolution: u16,
|
||||
pub y_resolution: u16,
|
||||
pub x_mirror: bool,
|
||||
pub y_mirror: bool,
|
||||
pub x_size: f32,
|
||||
pub y_size: f32,
|
||||
pub z_size: f32,
|
||||
pub layer_thickness: f32,
|
||||
pub exposure_time: f32,
|
||||
pub exposure_delay_mode: bool,
|
||||
pub turn_off_time: f32,
|
||||
pub bottom_before_lift_time: f32,
|
||||
pub bottom_after_lift_time: f32,
|
||||
pub bottom_after_retract_time: f32,
|
||||
pub before_lift_time: f32,
|
||||
pub after_lift_time: f32,
|
||||
pub after_retract_time: f32,
|
||||
pub bottom_exposure_time: f32,
|
||||
pub bottom_layers: u32,
|
||||
pub bottom_lift_distance: f32,
|
||||
pub bottom_lift_speed: f32,
|
||||
pub lift_distance: f32,
|
||||
pub lift_speed: f32,
|
||||
pub bottom_retract_distance: f32,
|
||||
pub bottom_retract_speed: f32,
|
||||
pub retract_distance: f32,
|
||||
pub retract_speed: f32,
|
||||
pub bottom_second_lift_distance: f32,
|
||||
pub bottom_second_lift_speed: f32,
|
||||
pub second_lift_distance: f32,
|
||||
pub second_lift_speed: f32,
|
||||
pub bottom_second_retract_distance: f32,
|
||||
pub bottom_second_retract_speed: f32,
|
||||
pub second_retract_distance: f32,
|
||||
pub second_retract_speed: f32,
|
||||
pub bottom_light_pwm: u16,
|
||||
pub light_pwm: u16,
|
||||
pub advance_mode: bool,
|
||||
pub printing_time: u32,
|
||||
pub total_volume: f32,
|
||||
pub total_weight: f32,
|
||||
pub total_price: f32,
|
||||
pub price_unit: SizedString<8>,
|
||||
pub grey_scale_level: bool,
|
||||
pub transition_layers: u16,
|
||||
}
|
||||
|
||||
pub struct LayerContent {
|
||||
pub pause_flag: u16,
|
||||
pub pause_position_z: f32,
|
||||
pub layer_position_z: f32,
|
||||
pub layer_exposure_time: f32,
|
||||
pub layer_off_time: f32,
|
||||
pub before_lift_time: f32,
|
||||
pub after_lift_time: f32,
|
||||
pub after_retract_time: f32,
|
||||
pub lift_distance: f32,
|
||||
pub lift_speed: f32,
|
||||
pub second_lift_distance: f32,
|
||||
pub second_lift_speed: f32,
|
||||
pub retract_distance: f32,
|
||||
pub retract_speed: f32,
|
||||
pub second_retract_distance: f32,
|
||||
pub second_retract_speed: f32,
|
||||
pub light_pwm: u16,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub struct PreviewImage<const WIDTH: usize, const HEIGHT: usize> {
|
||||
data: [[u16; WIDTH]; HEIGHT],
|
||||
}
|
||||
|
||||
pub struct EncodedLayer {
|
||||
data: Vec<u8>,
|
||||
last_value: u8,
|
||||
}
|
||||
|
||||
impl<const WIDTH: usize, const HEIGHT: usize> PreviewImage<WIDTH, HEIGHT> {
|
||||
pub const fn empty() -> Self {
|
||||
Self {
|
||||
data: [[0; WIDTH]; HEIGHT],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serializes(&self, serializer: &mut Serializer) {
|
||||
for row in self.data.iter() {
|
||||
for pixel in row.iter() {
|
||||
serializer.write_u16(*pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EncodedLayer {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
data: Vec::new(),
|
||||
last_value: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_run(&mut self, length: u64, value: u8) {
|
||||
// byte 0: aabbcccc
|
||||
// a => 0: full black, 1: full white, 2: small diff, 3: large diff
|
||||
// b => 0: 4 bit length, 1: 12 bit value, 2: 20 bit value, 3: 28 bit value
|
||||
// c => the first 4 bits of the value
|
||||
// byte 1-3: optional, the rest of the value
|
||||
|
||||
let diff = value as i16 - self.last_value as i16;
|
||||
let byte_0: u8 = match value {
|
||||
// Full black and full white are always encoded as is
|
||||
0x00 => 0b00,
|
||||
0xFF => 0b11,
|
||||
_ if !self.data.is_empty() && diff.abs() <= 15 => {
|
||||
// 0babcccc
|
||||
// a => 0: add diff, 1: sub diff
|
||||
// b => 0: length of 1, 1: length is next byte
|
||||
// c => the diff
|
||||
|
||||
if length > 255 {
|
||||
self.add_run(255, value);
|
||||
self.add_run(length - 255, value);
|
||||
return;
|
||||
}
|
||||
|
||||
let byte_0 = (0b10 << 6)
|
||||
| (((diff > 0) as u8) << 5)
|
||||
| (((length != 1) as u8) << 4)
|
||||
| (diff.abs() as u8);
|
||||
self.data.push(byte_0);
|
||||
|
||||
if length != 1 {
|
||||
self.data.push(length as u8);
|
||||
}
|
||||
|
||||
self.last_value = value;
|
||||
return;
|
||||
}
|
||||
_ => 0b01,
|
||||
} << 6;
|
||||
|
||||
let chunk_length_size = match length {
|
||||
0x0000000..=0x000000F => 0b00,
|
||||
0x0000010..=0x0000FFF => 0b01,
|
||||
0x0001000..=0x00FFFFF => 0b10,
|
||||
0x0100000..=0xFFFFFFF => 0b11,
|
||||
_ => {
|
||||
self.add_run(0xFFFFFFF, value);
|
||||
self.add_run(length - 0xFFFFFFF, value);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
self.data
|
||||
.push(byte_0 | (chunk_length_size << 4) | (length as u8 & 0x0F));
|
||||
match chunk_length_size {
|
||||
1 => self.data.extend_from_slice(&[(length >> 4) as u8]),
|
||||
2 => self
|
||||
.data
|
||||
.extend_from_slice(&[(length >> 12) as u8, (length >> 4) as u8]),
|
||||
3 => self.data.extend_from_slice(&[
|
||||
(length >> 20) as u8,
|
||||
(length >> 12) as u8,
|
||||
(length >> 4) as u8,
|
||||
]),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.last_value = value;
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderInfo {
|
||||
pub const SIZE: usize = 0x2FB95;
|
||||
|
||||
pub fn serialize(&self, buf: &mut [u8]) {
|
||||
let mut ser = Serializer::new(buf);
|
||||
ser.write_sized_string(&self.version);
|
||||
ser.write_bytes(&[0x07, 0x00, 0x00, 0x00, 0x44, 0x4C, 0x50, 0x00]);
|
||||
ser.write_sized_string(&self.software_info);
|
||||
ser.write_sized_string(&self.software_version);
|
||||
ser.write_sized_string(&self.file_time);
|
||||
ser.write_sized_string(&self.printer_name);
|
||||
ser.write_sized_string(&self.printer_type);
|
||||
ser.write_sized_string(&self.profile_name);
|
||||
ser.write_u16(self.anti_aliasing_level);
|
||||
ser.write_u16(self.grey_level);
|
||||
ser.write_u16(self.blur_level);
|
||||
self.small_preview.serializes(&mut ser);
|
||||
ser.write_bytes(&[0xd, 0xa]);
|
||||
self.big_preview.serializes(&mut ser);
|
||||
ser.write_bytes(&[0xd, 0xa]);
|
||||
ser.write_u32(self.layer_count);
|
||||
ser.write_u16(self.x_resolution);
|
||||
ser.write_u16(self.y_resolution);
|
||||
ser.write_bool(self.x_mirror);
|
||||
ser.write_bool(self.y_mirror);
|
||||
ser.write_f32(self.x_size);
|
||||
ser.write_f32(self.y_size);
|
||||
ser.write_f32(self.z_size);
|
||||
ser.write_f32(self.layer_thickness);
|
||||
ser.write_f32(self.exposure_time);
|
||||
ser.write_bool(self.exposure_delay_mode);
|
||||
ser.write_f32(self.turn_off_time);
|
||||
ser.write_f32(self.bottom_before_lift_time);
|
||||
ser.write_f32(self.bottom_after_lift_time);
|
||||
ser.write_f32(self.bottom_after_retract_time);
|
||||
ser.write_f32(self.before_lift_time);
|
||||
ser.write_f32(self.after_lift_time);
|
||||
ser.write_f32(self.after_retract_time);
|
||||
ser.write_f32(self.bottom_exposure_time);
|
||||
ser.write_u32(self.bottom_layers);
|
||||
ser.write_f32(self.bottom_lift_distance);
|
||||
ser.write_f32(self.bottom_lift_speed);
|
||||
ser.write_f32(self.lift_distance);
|
||||
ser.write_f32(self.lift_speed);
|
||||
ser.write_f32(self.bottom_retract_distance);
|
||||
ser.write_f32(self.bottom_retract_speed);
|
||||
ser.write_f32(self.retract_distance);
|
||||
ser.write_f32(self.retract_speed);
|
||||
ser.write_f32(self.bottom_second_lift_distance);
|
||||
ser.write_f32(self.bottom_second_lift_speed);
|
||||
ser.write_f32(self.second_lift_distance);
|
||||
ser.write_f32(self.second_lift_speed);
|
||||
ser.write_f32(self.bottom_second_retract_distance);
|
||||
ser.write_f32(self.bottom_second_retract_speed);
|
||||
ser.write_f32(self.second_retract_distance);
|
||||
ser.write_f32(self.second_retract_speed);
|
||||
ser.write_u16(self.bottom_light_pwm);
|
||||
ser.write_u16(self.light_pwm);
|
||||
ser.write_bool(self.advance_mode);
|
||||
ser.write_u32(self.printing_time);
|
||||
ser.write_f32(self.total_volume);
|
||||
ser.write_f32(self.total_weight);
|
||||
ser.write_f32(self.total_price);
|
||||
ser.write_sized_string(&self.price_unit);
|
||||
ser.write_u32(Self::SIZE as u32);
|
||||
ser.write_bool(self.grey_scale_level);
|
||||
ser.write_u16(self.transition_layers);
|
||||
}
|
||||
}
|
||||
|
||||
impl LayerContent {
|
||||
pub fn serialize(&self, buf: &mut [u8]) {
|
||||
let mut ser = Serializer::new(buf);
|
||||
ser.write_u16(self.pause_flag);
|
||||
ser.write_f32(self.pause_position_z);
|
||||
ser.write_f32(self.layer_position_z);
|
||||
ser.write_f32(self.layer_exposure_time);
|
||||
ser.write_f32(self.layer_off_time);
|
||||
ser.write_f32(self.before_lift_time);
|
||||
ser.write_f32(self.after_lift_time);
|
||||
ser.write_f32(self.after_retract_time);
|
||||
ser.write_f32(self.lift_distance);
|
||||
ser.write_f32(self.lift_speed);
|
||||
ser.write_f32(self.second_lift_distance);
|
||||
ser.write_f32(self.second_lift_speed);
|
||||
ser.write_f32(self.retract_distance);
|
||||
ser.write_f32(self.retract_speed);
|
||||
ser.write_f32(self.second_retract_distance);
|
||||
ser.write_f32(self.second_retract_speed);
|
||||
ser.write_u16(self.light_pwm);
|
||||
ser.write_u32(self.data.len() as u32 + 2);
|
||||
ser.write_bytes(&[0x55]);
|
||||
ser.write_bytes(&self.data);
|
||||
ser.write_u8(self.calculate_checksum());
|
||||
ser.write_bytes(&[0xd, 0xa]);
|
||||
}
|
||||
|
||||
fn calculate_checksum(&self) -> u8 {
|
||||
let mut out = 0u8;
|
||||
for &byte in self.data.iter() {
|
||||
out = out.wrapping_add(byte);
|
||||
}
|
||||
!out
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HeaderInfo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
version: SizedString::new(b"V3.0"),
|
||||
software_info: SizedString::new(b"sla_slicer by Connor Slade"),
|
||||
software_version: SizedString::new(b"0.1.0"),
|
||||
file_time: SizedString::new(b"2024-06-14 08:10:14"),
|
||||
printer_name: SizedString::new(b"standard"),
|
||||
printer_type: SizedString::new(b"Default"),
|
||||
profile_name: SizedString::new(b"New Script"),
|
||||
anti_aliasing_level: 8,
|
||||
grey_level: 0,
|
||||
blur_level: 0,
|
||||
small_preview: PreviewImage::empty(),
|
||||
big_preview: PreviewImage::empty(),
|
||||
layer_count: 171,
|
||||
x_resolution: 11520,
|
||||
y_resolution: 5102,
|
||||
x_mirror: false,
|
||||
y_mirror: false,
|
||||
x_size: 218.88,
|
||||
y_size: 122.88,
|
||||
z_size: 260.0,
|
||||
layer_thickness: 0.05,
|
||||
exposure_time: 3.0,
|
||||
exposure_delay_mode: true,
|
||||
turn_off_time: 0.0,
|
||||
bottom_before_lift_time: 0.0,
|
||||
bottom_after_lift_time: 0.0,
|
||||
bottom_after_retract_time: 0.0,
|
||||
before_lift_time: 0.0,
|
||||
after_lift_time: 0.0,
|
||||
after_retract_time: 0.0,
|
||||
bottom_exposure_time: 50.0,
|
||||
bottom_layers: 8,
|
||||
bottom_lift_distance: 5.0,
|
||||
bottom_lift_speed: 65.0,
|
||||
lift_distance: 5.0,
|
||||
lift_speed: 65.0,
|
||||
bottom_retract_distance: 5.0,
|
||||
bottom_retract_speed: 150.0,
|
||||
retract_distance: 5.0,
|
||||
retract_speed: 0.0,
|
||||
bottom_second_lift_distance: 0.0,
|
||||
bottom_second_lift_speed: 0.0,
|
||||
second_lift_distance: 0.0,
|
||||
second_lift_speed: 0.0,
|
||||
bottom_second_retract_distance: 0.0,
|
||||
bottom_second_retract_speed: 0.0,
|
||||
second_retract_distance: 0.0,
|
||||
second_retract_speed: 0.0,
|
||||
bottom_light_pwm: 255,
|
||||
light_pwm: 255,
|
||||
advance_mode: false,
|
||||
printing_time: 2659,
|
||||
total_volume: 526.507,
|
||||
total_weight: 0.684,
|
||||
total_price: 0.0,
|
||||
price_unit: SizedString::new(b"$"),
|
||||
grey_scale_level: true,
|
||||
transition_layers: 10,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for LayerContent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
pause_flag: 0,
|
||||
pause_position_z: 200.0,
|
||||
layer_position_z: 0.05,
|
||||
layer_exposure_time: 50.0,
|
||||
layer_off_time: 0.0,
|
||||
before_lift_time: 0.0,
|
||||
after_lift_time: 0.0,
|
||||
after_retract_time: 0.0,
|
||||
lift_distance: 5.0,
|
||||
lift_speed: 65.0,
|
||||
second_lift_distance: 0.0,
|
||||
second_lift_speed: 0.0,
|
||||
retract_distance: 5.0,
|
||||
retract_speed: 150.0,
|
||||
second_retract_distance: 0.0,
|
||||
second_retract_speed: 0.0,
|
||||
light_pwm: 255,
|
||||
data: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub use encoded_layer::{LayerDecoder, LayerEncoder, Run};
|
||||
pub use file::File;
|
||||
pub use header_info::HeaderInfo;
|
||||
pub use layer_content::LayerContent;
|
||||
pub use preview_image::PreviewImage;
|
||||
|
65
goo_format/src/main.rs
Normal file
65
goo_format/src/main.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use clap::Parser;
|
||||
use goo_format::{File, LayerDecoder, Run};
|
||||
use image::RgbImage;
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Args {
|
||||
/// Path to the .goo file
|
||||
input_file: PathBuf,
|
||||
|
||||
/// Path to output each layer as an image
|
||||
#[clap(short, long)]
|
||||
layers: Option<PathBuf>,
|
||||
|
||||
/// Do not print the header information
|
||||
#[clap(short, long)]
|
||||
no_header: bool,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
let raw_goo = fs::read(&args.input_file)?;
|
||||
let goo = File::deserialize(&raw_goo)?;
|
||||
|
||||
if !args.no_header {
|
||||
println!("{:#?}", goo.header);
|
||||
}
|
||||
|
||||
if let Some(layers) = args.layers {
|
||||
fs::create_dir_all(&layers)?;
|
||||
|
||||
for (i, layer) in goo.layers.iter().enumerate() {
|
||||
let decoder = LayerDecoder::new(&layer.data);
|
||||
let mut pixel = 0;
|
||||
|
||||
if layer.checksum != decoder.checksum() {
|
||||
eprintln!("WARN: Checksum mismatch for layer {}", i);
|
||||
}
|
||||
|
||||
let path = layers.join(format!("layer_{:03}.png", i));
|
||||
let mut image = RgbImage::new(
|
||||
goo.header.x_resolution as u32,
|
||||
goo.header.y_resolution as u32,
|
||||
);
|
||||
|
||||
for Run { length, value } in decoder {
|
||||
for _ in 0..length {
|
||||
let x = pixel % goo.header.x_resolution as u32;
|
||||
let y = pixel / goo.header.x_resolution as u32;
|
||||
|
||||
image.put_pixel(x, y, image::Rgb([value, value, value]));
|
||||
|
||||
pixel += 1;
|
||||
}
|
||||
}
|
||||
|
||||
image.save(path)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
47
goo_format/src/preview_image.rs
Normal file
47
goo_format/src/preview_image.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use common::serde::{Deserializer, Serializer};
|
||||
|
||||
pub struct PreviewImage<const WIDTH: usize, const HEIGHT: usize> {
|
||||
// 0brrrrrggggggbbbbb
|
||||
data: [[u16; WIDTH]; HEIGHT],
|
||||
}
|
||||
|
||||
impl<const WIDTH: usize, const HEIGHT: usize> PreviewImage<WIDTH, HEIGHT> {
|
||||
pub const fn empty() -> Self {
|
||||
Self {
|
||||
data: [[0; WIDTH]; HEIGHT],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn serializes<T: Serializer>(&self, serializer: &mut T) {
|
||||
for row in self.data.iter() {
|
||||
for pixel in row.iter() {
|
||||
serializer.write_u16(*pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserializes(deserializer: &mut Deserializer) -> Self {
|
||||
let mut data = [[0; WIDTH]; HEIGHT];
|
||||
for row in data.iter_mut() {
|
||||
for pixel in row.iter_mut() {
|
||||
*pixel = deserializer.read_u16();
|
||||
}
|
||||
}
|
||||
Self { data }
|
||||
}
|
||||
|
||||
pub fn set_pixel(&mut self, x: usize, y: usize, color: (f32, f32, f32)) {
|
||||
let red = (color.0 * 31.0).round() as u16;
|
||||
let green = (color.1 * 63.0).round() as u16;
|
||||
let blue = (color.2 * 31.0).round() as u16;
|
||||
self.data[y][x] = (red << 11) | (green << 5) | blue;
|
||||
}
|
||||
|
||||
pub fn get_pixel(&self, x: usize, y: usize) -> (f32, f32, f32) {
|
||||
let pixel = self.data[y][x];
|
||||
let red = ((pixel >> 11) & 0x1F) as f32 / 31.0;
|
||||
let green = ((pixel >> 5) & 0x3F) as f32 / 63.0;
|
||||
let blue = (pixel & 0x1F) as f32 / 31.0;
|
||||
(red, green, blue)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user