1
1
use crate :: read_extension:: ReadExt ;
2
2
use crate :: tmf:: SectionType ;
3
- use crate :: { FloatType , IndexType , TMFImportError , MAX_SEG_SIZE } ;
3
+ use crate :: { FloatType , IndexType , TMFImportError , MAX_SEG_SIZE , Vector4 } ;
4
4
#[ derive( Clone , Debug ) ]
5
5
pub ( crate ) struct CustomDataSegment {
6
6
name : Vec < u8 > ,
@@ -50,27 +50,34 @@ pub enum CustomData {
50
50
CustomIndex ( Box < [ IndexType ] > , usize ) ,
51
51
CustomIntiger ( Box < [ IndexType ] > , usize ) ,
52
52
CustomFloat ( Box < [ FloatType ] > , FloatType ) ,
53
+ CustomColorRGBA ( Box < [ Vector4 ] > , FloatType ) ,
53
54
}
54
55
impl CustomData {
55
56
/// 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 ) > {
57
58
match self {
58
59
Self :: CustomIndex ( array, max_index) => Some ( ( array, * max_index) ) ,
59
60
_ => None ,
60
61
}
61
62
}
62
- pub fn is_intiger ( & self ) -> Option < ( & [ IndexType ] , usize ) > {
63
+ pub fn as_intiger ( & self ) -> Option < ( & [ IndexType ] , usize ) > {
63
64
match self {
64
65
Self :: CustomIntiger ( array, max_index) => Some ( ( array, * max_index) ) ,
65
66
_ => None ,
66
67
}
67
68
}
68
- pub fn is_float ( & self ) -> Option < ( & [ FloatType ] , FloatType ) > {
69
+ pub fn as_float ( & self ) -> Option < ( & [ FloatType ] , FloatType ) > {
69
70
match self {
70
71
Self :: CustomFloat ( array, prec) => Some ( ( array, * prec) ) ,
71
72
_ => None ,
72
73
}
73
74
}
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
+ }
74
81
fn write < W : std:: io:: Write > ( & self , target : & mut W ) -> std:: io:: Result < ( ) > {
75
82
match self {
76
83
Self :: CustomIndex ( data, max_index) => {
@@ -79,7 +86,7 @@ impl CustomData {
79
86
Self :: CustomIntiger ( data, max_index) => {
80
87
crate :: vertices:: save_triangles ( data, * max_index, target)
81
88
}
82
- CustomData :: CustomFloat ( data, prec) => {
89
+ Self :: CustomFloat ( data, prec) => {
83
90
use crate :: unaligned_rw:: { UnalignedRWMode , UnalignedWriter } ;
84
91
let mut max = FloatType :: MIN ;
85
92
let mut min = FloatType :: MAX ;
@@ -104,6 +111,26 @@ impl CustomData {
104
111
}
105
112
Ok ( ( ) )
106
113
}
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
+ }
107
134
} ?;
108
135
Ok ( ( ) )
109
136
}
@@ -112,11 +139,15 @@ impl CustomData {
112
139
Self :: CustomIndex ( _, _) => SectionType :: CustomIndexSegment ,
113
140
Self :: CustomIntiger ( _, _) => SectionType :: CustomIntigerSegment ,
114
141
Self :: CustomFloat ( _, _) => SectionType :: CustomFloatSegment ,
142
+ Self :: CustomColorRGBA ( _, _) => SectionType :: CustomColorRGBASegment ,
115
143
}
116
144
}
117
145
fn new_float ( floats : & [ FloatType ] , prec : FloatType ) -> Self {
118
146
Self :: CustomFloat ( floats. into ( ) , prec)
119
147
}
148
+ fn new_color_rgba ( colors : & [ Vector4 ] , prec : FloatType ) -> Self {
149
+ Self :: CustomColorRGBA ( colors. into ( ) , prec)
150
+ }
120
151
fn new_index ( indices : & [ IndexType ] , max_index : Option < usize > ) -> Self {
121
152
let max_index = match max_index {
122
153
Some ( max_index) => max_index,
@@ -142,6 +173,11 @@ impl From<&[FloatType]> for CustomData {
142
173
Self :: new_float ( floats, 0.01 )
143
174
}
144
175
}
176
+ impl From < & [ Vector4 ] > for CustomData {
177
+ fn from ( colors : & [ Vector4 ] ) -> Self {
178
+ Self :: new_color_rgba ( colors, 0.01 )
179
+ }
180
+ }
145
181
impl CustomDataSegment {
146
182
pub ( crate ) fn encode < W : std:: io:: Write > ( & self , target : & mut W ) -> std:: io:: Result < SectionType > {
147
183
target. write_all ( & [ self . name_len ] ) ?;
@@ -159,6 +195,9 @@ impl CustomDataSegment {
159
195
let mut name = [ 0 ; u8:: MAX as usize ] ;
160
196
src. read_exact ( & mut name[ ..( name_len as usize ) ] ) ?;
161
197
match kind {
198
+ /*SectionType::CustomColorSegment =>{
199
+
200
+ }*/
162
201
SectionType :: CustomIndexSegment => {
163
202
let result = crate :: vertices:: read_triangles ( & mut src, ctx) ?;
164
203
Ok ( Self :: new_raw (
@@ -204,6 +243,26 @@ impl CustomDataSegment {
204
243
name_len,
205
244
) )
206
245
}
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
+ }
207
266
_ => panic ! ( "InternalError: Invalid custom section type, must be custom!" ) ,
208
267
}
209
268
}
@@ -236,7 +295,7 @@ fn index_data() {
236
295
let read_indices = r_mesh
237
296
. lookup_custom_data ( "custom_index" )
238
297
. 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 ( ) ;
240
299
assert_eq ! ( index_data, read_indices) ;
241
300
}
242
301
#[ test]
@@ -266,7 +325,7 @@ fn float_data() {
266
325
. lookup_custom_data ( "custom_float" )
267
326
. expect ( "Could not find the custom float array!" ) ;
268
327
269
- let ( read_floats, _) = read_floats. is_float ( ) . unwrap ( ) ;
328
+ let ( read_floats, _) = read_floats. as_float ( ) . unwrap ( ) ;
270
329
271
330
for index in 0 ..read_floats. len ( ) {
272
331
assert ! (
@@ -278,3 +337,62 @@ fn float_data() {
278
337
) ;
279
338
}
280
339
}
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
+ }
0 commit comments