Skip to content

Commit 6f7598a

Browse files
committed
Added support for RGBA color custom data.
1 parent 545b4ad commit 6f7598a

File tree

5 files changed

+133
-11
lines changed

5 files changed

+133
-11
lines changed

src/custom_data.rs

+125-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::read_extension::ReadExt;
22
use crate::tmf::SectionType;
3-
use crate::{FloatType, IndexType, TMFImportError, MAX_SEG_SIZE};
3+
use crate::{FloatType, IndexType, TMFImportError, MAX_SEG_SIZE,Vector4};
44
#[derive(Clone, Debug)]
55
pub(crate) struct CustomDataSegment {
66
name: Vec<u8>,
@@ -50,27 +50,34 @@ pub enum CustomData {
5050
CustomIndex(Box<[IndexType]>, usize),
5151
CustomIntiger(Box<[IndexType]>, usize),
5252
CustomFloat(Box<[FloatType]>, FloatType),
53+
CustomColorRGBA(Box<[Vector4]>, FloatType),
5354
}
5455
impl CustomData {
5556
/// Returns the index data if custom segment is an index segment. Returns the index array and max index.
56-
pub fn is_index(&self) -> Option<(&[IndexType], usize)> {
57+
pub fn as_index(&self) -> Option<(&[IndexType], usize)> {
5758
match self {
5859
Self::CustomIndex(array, max_index) => Some((array, *max_index)),
5960
_ => None,
6061
}
6162
}
62-
pub fn is_intiger(&self) -> Option<(&[IndexType], usize)> {
63+
pub fn as_intiger(&self) -> Option<(&[IndexType], usize)> {
6364
match self {
6465
Self::CustomIntiger(array, max_index) => Some((array, *max_index)),
6566
_ => None,
6667
}
6768
}
68-
pub fn is_float(&self) -> Option<(&[FloatType], FloatType)> {
69+
pub fn as_float(&self) -> Option<(&[FloatType], FloatType)> {
6970
match self {
7071
Self::CustomFloat(array, prec) => Some((array, *prec)),
7172
_ => None,
7273
}
7374
}
75+
pub fn as_color_rgba(&self) -> Option<(&[Vector4], FloatType)> {
76+
match self {
77+
Self::CustomColorRGBA(array, prec) => Some((array, *prec)),
78+
_ => None,
79+
}
80+
}
7481
fn write<W: std::io::Write>(&self, target: &mut W) -> std::io::Result<()> {
7582
match self {
7683
Self::CustomIndex(data, max_index) => {
@@ -79,7 +86,7 @@ impl CustomData {
7986
Self::CustomIntiger(data, max_index) => {
8087
crate::vertices::save_triangles(data, *max_index, target)
8188
}
82-
CustomData::CustomFloat(data, prec) => {
89+
Self::CustomFloat(data, prec) => {
8390
use crate::unaligned_rw::{UnalignedRWMode, UnalignedWriter};
8491
let mut max = FloatType::MIN;
8592
let mut min = FloatType::MAX;
@@ -104,6 +111,26 @@ impl CustomData {
104111
}
105112
Ok(())
106113
}
114+
Self::CustomColorRGBA(data,prec)=>{
115+
use crate::unaligned_rw::{UnalignedRWMode, UnalignedWriter};
116+
let prec_bits = (1.0/prec.min(1.0)).log2().ceil() as u8;
117+
let mul = ((1 << prec_bits) - 1) as FloatType;
118+
target.write_all(&(data.len() as u64).to_le_bytes())?;
119+
target.write_all(&[prec_bits])?;
120+
let prec = UnalignedRWMode::precision_bits(prec_bits);
121+
let mut writer = UnalignedWriter::new(target);
122+
for entry in data.iter() {
123+
let entry_r = (entry.0 * mul) as u64;
124+
let entry_g = (entry.1 * mul) as u64;
125+
let entry_b = (entry.2 * mul) as u64;
126+
let entry_a = (entry.3 * mul) as u64;
127+
writer.write_unaligned(prec, entry_r)?;
128+
writer.write_unaligned(prec, entry_g)?;
129+
writer.write_unaligned(prec, entry_b)?;
130+
writer.write_unaligned(prec, entry_a)?;
131+
}
132+
Ok(())
133+
}
107134
}?;
108135
Ok(())
109136
}
@@ -112,11 +139,15 @@ impl CustomData {
112139
Self::CustomIndex(_, _) => SectionType::CustomIndexSegment,
113140
Self::CustomIntiger(_, _) => SectionType::CustomIntigerSegment,
114141
Self::CustomFloat(_, _) => SectionType::CustomFloatSegment,
142+
Self::CustomColorRGBA(_,_) => SectionType::CustomColorRGBASegment,
115143
}
116144
}
117145
fn new_float(floats: &[FloatType], prec: FloatType) -> Self {
118146
Self::CustomFloat(floats.into(), prec)
119147
}
148+
fn new_color_rgba(colors: &[Vector4], prec: FloatType) -> Self {
149+
Self::CustomColorRGBA(colors.into(), prec)
150+
}
120151
fn new_index(indices: &[IndexType], max_index: Option<usize>) -> Self {
121152
let max_index = match max_index {
122153
Some(max_index) => max_index,
@@ -142,6 +173,11 @@ impl From<&[FloatType]> for CustomData {
142173
Self::new_float(floats, 0.01)
143174
}
144175
}
176+
impl From<&[Vector4]> for CustomData {
177+
fn from(colors: &[Vector4]) -> Self {
178+
Self::new_color_rgba(colors, 0.01)
179+
}
180+
}
145181
impl CustomDataSegment {
146182
pub(crate) fn encode<W: std::io::Write>(&self, target: &mut W) -> std::io::Result<SectionType> {
147183
target.write_all(&[self.name_len])?;
@@ -159,6 +195,9 @@ impl CustomDataSegment {
159195
let mut name = [0; u8::MAX as usize];
160196
src.read_exact(&mut name[..(name_len as usize)])?;
161197
match kind {
198+
/*SectionType::CustomColorSegment =>{
199+
200+
}*/
162201
SectionType::CustomIndexSegment => {
163202
let result = crate::vertices::read_triangles(&mut src, ctx)?;
164203
Ok(Self::new_raw(
@@ -204,6 +243,26 @@ impl CustomDataSegment {
204243
name_len,
205244
))
206245
}
246+
SectionType::CustomColorRGBASegment=>{
247+
use crate::unaligned_rw::{UnalignedRWMode, UnalignedReader};
248+
let len = src.read_u64()?;
249+
let prec_bits = src.read_u8()?;
250+
let prec = UnalignedRWMode::precision_bits(prec_bits);
251+
let mut reader = UnalignedReader::new(src);
252+
let mut res = vec![(0.0,0.0,0.0,0.0); len as usize];
253+
let div = ((1_u64 << prec_bits) - 1) as f64;
254+
for vec4 in &mut res {
255+
let (r,g) = reader.read2_unaligned(prec)?;
256+
let (b,a) = reader.read2_unaligned(prec)?;
257+
*vec4 = (((r as f64) / div) as FloatType,((g as f64) / div) as FloatType,((b as f64) / div) as FloatType,((a as f64) / div) as FloatType);
258+
}
259+
let prec = ((1.0 / ((1_u64 << prec_bits) as f64)) as FloatType) * 0.99999;
260+
Ok(Self::new_raw(
261+
CustomData::new_color_rgba(&res, prec),
262+
name,
263+
name_len,
264+
))
265+
}
207266
_ => panic!("InternalError: Invalid custom section type, must be custom!"),
208267
}
209268
}
@@ -236,7 +295,7 @@ fn index_data() {
236295
let read_indices = r_mesh
237296
.lookup_custom_data("custom_index")
238297
.expect("Could not find the custom index array!");
239-
let (read_indices, _) = read_indices.is_index().unwrap();
298+
let (read_indices, _) = read_indices.as_index().unwrap();
240299
assert_eq!(index_data, read_indices);
241300
}
242301
#[test]
@@ -266,7 +325,7 @@ fn float_data() {
266325
.lookup_custom_data("custom_float")
267326
.expect("Could not find the custom float array!");
268327

269-
let (read_floats, _) = read_floats.is_float().unwrap();
328+
let (read_floats, _) = read_floats.as_float().unwrap();
270329

271330
for index in 0..read_floats.len() {
272331
assert!(
@@ -278,3 +337,62 @@ fn float_data() {
278337
);
279338
}
280339
}
340+
#[test]
341+
#[cfg(all(feature = "obj_import", test))]
342+
fn color_rgba_data() {
343+
use crate::{TMFMesh, TMFPrecisionInfo};
344+
init_test_env();
345+
let mut file = std::fs::File::open("testing/susan.obj").unwrap();
346+
let (mut tmf_mesh, name) = TMFMesh::read_from_obj_one(&mut file).unwrap();
347+
let color_rgba_data: [Vector4; 3] = [
348+
(0.9, 0.19, 0.2, 0.7867), (0.431224, 0.534345, 0.64336, 0.78634), (0.776565, 0.87575, 0.954,0.3543)
349+
];
350+
tmf_mesh
351+
.add_custom_data(color_rgba_data[..].into(), "custom_color_rgba")
352+
.unwrap();
353+
tmf_mesh.verify().unwrap();
354+
assert!(name == "Suzanne", "Name should be Suzanne but is {name}");
355+
let prec = TMFPrecisionInfo::default();
356+
let mut out = Vec::new();
357+
{
358+
tmf_mesh.write_tmf_one(&mut out, &prec, name).unwrap();
359+
}
360+
let (r_mesh, name) = TMFMesh::read_tmf_one(&mut (&out as &[u8])).unwrap();
361+
assert!(name == "Suzanne", "Name should be Suzanne but is {name}");
362+
r_mesh.verify().unwrap();
363+
let read_color_rgbas = r_mesh
364+
.lookup_custom_data("custom_color_rgba")
365+
.expect("Could not find the custom color_rgba array!");
366+
367+
let (read_color_rgbas, _) = read_color_rgbas.as_color_rgba().unwrap();
368+
for index in 0..read_color_rgbas.len() {
369+
assert!(
370+
(read_color_rgbas[index].0 - color_rgba_data[index].0).abs() <= 0.01,
371+
"{} diff {:?} {:?} > 0.01!",
372+
index,
373+
read_color_rgbas[index],
374+
color_rgba_data[index]
375+
);
376+
assert!(
377+
(read_color_rgbas[index].1 - color_rgba_data[index].1).abs() <= 0.01,
378+
"{} diff {:?} {:?} > 0.01!",
379+
index,
380+
read_color_rgbas[index],
381+
color_rgba_data[index]
382+
);
383+
assert!(
384+
(read_color_rgbas[index].2 - color_rgba_data[index].2).abs() <= 0.01,
385+
"{} diff {:?} {:?} > 0.01!",
386+
index,
387+
read_color_rgbas[index],
388+
color_rgba_data[index]
389+
);
390+
assert!(
391+
(read_color_rgbas[index].3 - color_rgba_data[index].3).abs() <= 0.01,
392+
"{} diff {:?} {:?} > 0.01!",
393+
index,
394+
read_color_rgbas[index],
395+
color_rgba_data[index]
396+
);
397+
}
398+
}

src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub type FloatType = f32;
7171
pub type FloatType = f64;
7272
/// Type used for representing 3d floating-point vectors
7373
pub type Vector3 = (FloatType, FloatType, FloatType);
74+
pub type Vector4 = (FloatType, FloatType, FloatType, FloatType);
7475
/// Type used for representing 2d floating-point vectors
7576
pub type Vector2 = (FloatType, FloatType);
7677
use crate::custom_data::CustomDataSegment;
@@ -1005,7 +1006,7 @@ mod testing {
10051006
&mut (&out as &[u8]),
10061007
))
10071008
.unwrap();
1008-
todo!();
1009+
//todo!();
10091010
}
10101011
#[test]
10111012
#[cfg(feature = "obj_import")]

src/reorder_triangles.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,5 @@ fn read_susan_obj() {
8585
.write_tmf_one(&mut out, &TMFPrecisionInfo::default(), "SUSAN")
8686
.unwrap();
8787

88-
todo!();
88+
//todo!();
8989
}

src/tmf.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub(crate) enum SectionType {
3535
CustomVector2Segment = 19,
3636
CustomVector3Segment = 20,
3737
CustomVector4Segment = 21,
38-
CustomColorSegment = 23,
38+
CustomColorRGBASegment = 23,
3939
CustomIntigerSegment = 24,
4040
SharedTriangleSegment = 25,
4141
}
@@ -70,6 +70,7 @@ impl SectionType {
7070
10 => Self::TangentTriangleSegment,
7171
15 => Self::CustomIndexSegment,
7272
16 => Self::CustomFloatSegment,
73+
23 => Self::CustomColorRGBASegment,
7374
24 => Self::CustomIntigerSegment,
7475
25 => Self::SharedTriangleSegment,
7576
_ => Self::Invalid,
@@ -418,7 +419,8 @@ impl DecodedSegment {
418419
| SectionType::TangentTriangleSegment => decode_triangle_seg(seg, ctx).await,
419420
SectionType::CustomIndexSegment
420421
| SectionType::CustomIntigerSegment
421-
| SectionType::CustomFloatSegment => decode_custom_seg(seg, ctx).await,
422+
| SectionType::CustomFloatSegment |
423+
SectionType::CustomColorRGBASegment => decode_custom_seg(seg, ctx).await,
422424
SectionType::SharedTriangleSegment => {
423425
if seg.data.len() < 1 {
424426
return Err(TMFImportError::IO(std::io::Error::from(

src/tmf_importer.rs

+1
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,7 @@ pub(crate) async fn decode_custom_seg(
241241
SectionType::CustomIndexSegment
242242
| SectionType::CustomFloatSegment
243243
| SectionType::CustomIntigerSegment
244+
| SectionType::CustomColorRGBASegment
244245
) {
245246
let mut data: &[u8] = seg.data();
246247
Ok(DecodedSegment::AppendCustom(CustomDataSegment::read(

0 commit comments

Comments
 (0)