1use std::io::Write;
2
3use crate::owned::*;
4
5impl Puppet {
22 pub fn to_bytes(&self) -> Vec<u8> {
23 let mut buf = Vec::new();
24 self.write_to(&mut buf).expect("write to Vec never fails");
25 buf
26 }
27
28 pub fn write_to<W: Write>(&self, w: &mut W) -> std::io::Result<()> {
29 let mut json_buf = Vec::new();
31 {
32 let mut jw = JsonWriter::new(&mut json_buf);
33 self.write_json(&mut jw);
34 }
35
36 w.write_all(b"TRNSRTS\0")?;
38 w.write_all(&(json_buf.len() as u32).to_be_bytes())?;
39 w.write_all(&json_buf)?;
40
41 w.write_all(b"TEX_SECT")?;
43 w.write_all(&(self.textures.len() as u32).to_be_bytes())?;
44
45 for tex in &self.textures {
46 let data = match &tex.data {
47 TextureData::Encoded(d) => d.as_slice(),
48 TextureData::Rgba(d) => d.as_slice(),
49 };
50 w.write_all(&(data.len() as u32).to_be_bytes())?;
51 w.write_all(&[tex.format as u8])?;
52 w.write_all(data)?;
53 }
54
55 if !self.vendors.is_empty() {
57 w.write_all(b"EXT_SECT")?;
58 w.write_all(&(self.vendors.len() as u32).to_be_bytes())?;
59
60 for vendor in &self.vendors {
61 let name_bytes = vendor.name.as_bytes();
62 w.write_all(&(name_bytes.len() as u32).to_be_bytes())?;
63 w.write_all(name_bytes)?;
64
65 let payload = json::stringify(vendor.data.clone()).into_bytes();
66 w.write_all(&(payload.len() as u32).to_be_bytes())?;
67 w.write_all(&payload)?;
68 }
69 }
70
71 Ok(())
72 }
73
74 pub fn save<P: AsRef<std::path::Path>>(&self, path: P) -> std::io::Result<()> {
75 let mut file = std::fs::File::create(path)?;
76 self.write_to(&mut file)
77 }
78}
79
80struct JsonWriter<'w, W: Write> {
81 w: &'w mut W,
82}
83
84impl<'w, W: Write> JsonWriter<'w, W> {
85 fn new(w: &'w mut W) -> Self {
86 Self { w }
87 }
88
89 fn raw(&mut self, s: &str) {
90 let _ = self.w.write_all(s.as_bytes());
91 }
92
93 fn comma(&mut self) {
94 self.raw(",");
95 }
96
97 fn key(&mut self, k: &str) {
98 self.raw("\"");
99 self.raw(k);
100 self.raw("\":");
101 }
102
103 fn str_val(&mut self, s: &str) {
104 self.raw("\"");
105 for c in s.chars() {
107 match c {
108 '"' => self.raw("\\\""),
109 '\\' => self.raw("\\\\"),
110 '\n' => self.raw("\\n"),
111 '\r' => self.raw("\\r"),
112 '\t' => self.raw("\\t"),
113 c if (c as u32) < 0x20 => {
114 let _ = write!(self.w, "\\u{:04x}", c as u32);
115 }
116 c => {
117 let mut buf = [0u8; 4];
118 let s = c.encode_utf8(&mut buf);
119 let _ = self.w.write_all(s.as_bytes());
120 }
121 }
122 }
123 self.raw("\"");
124 }
125
126 fn null(&mut self) {
127 self.raw("null");
128 }
129
130 fn bool_val(&mut self, b: bool) {
131 self.raw(if b { "true" } else { "false" });
132 }
133
134 fn u32_val(&mut self, v: u32) {
135 let _ = write!(self.w, "{}", v);
136 }
137
138 fn _i32_val(&mut self, v: i32) {
139 let _ = write!(self.w, "{}", v);
140 }
141
142 fn f32_val(&mut self, v: f32) {
145 if v.is_nan() {
146 self.raw("0.0");
147 return;
148 }
149 if v.is_infinite() {
150 if v > 0.0 {
151 self.raw("1e38");
152 } else {
153 self.raw("-1e38");
154 }
155 return;
156 }
157
158 let s = format!("{}", v);
160 if s.contains('.') || s.contains('e') || s.contains('E') {
161 let _ = self.w.write_all(s.as_bytes());
162 } else {
163 let _ = self.w.write_all(s.as_bytes());
165 self.raw(".0");
166 }
167 }
168
169 fn f32_arr(&mut self, vals: &[f32]) {
170 self.raw("[");
171 for (i, &v) in vals.iter().enumerate() {
172 if i > 0 {
173 self.comma();
174 }
175 self.f32_val(v);
176 }
177 self.raw("]");
178 }
179
180 fn vec2(&mut self, v: [f32; 2]) {
181 self.f32_arr(&v);
182 }
183
184 fn vec3(&mut self, v: [f32; 3]) {
185 self.f32_arr(&v);
186 }
187
188 fn opt_str(&mut self, s: Option<&str>) {
189 match s {
190 Some(s) => self.str_val(s),
191 None => self.null(),
192 }
193 }
194
195 fn begin_obj(&mut self) {
196 self.raw("{");
197 }
198
199 fn end_obj(&mut self) {
200 self.raw("}");
201 }
202
203 fn begin_arr(&mut self) {
204 self.raw("[");
205 }
206
207 fn end_arr(&mut self) {
208 self.raw("]");
209 }
210
211 fn json_value(&mut self, v: &json::JsonValue) {
213 let s = json::stringify(v.clone());
214 let _ = self.w.write_all(s.as_bytes());
215 }
216}
217
218impl Puppet {
219 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
220 j.begin_obj();
221 j.key("meta");
223 self.meta.write_json(j);
224 j.comma();
226 j.key("physics");
227 self.physics.write_json(j);
228 j.comma();
230 j.key("nodes");
231 self.nodes.write_json(j);
232 j.comma();
234 j.key("param");
235
236 j.begin_arr();
237 for (i, p) in self.params.values().enumerate() {
238 if i > 0 {
239 j.comma();
240 }
241 p.write_json(j);
242 }
243 j.end_arr();
244
245 j.comma();
247 j.key("automation");
248 j.null();
249 j.comma();
251 j.key("animations");
252 self.write_animations(j);
253 j.comma();
255 j.key("groups");
256 j.begin_arr();
257 for (i, g) in self.groups.iter().enumerate() {
258 if i > 0 {
259 j.comma();
260 }
261 g.write_json(j);
262 }
263 j.end_arr();
264
265 j.end_obj();
266 }
267
268 fn write_animations<W: Write>(&self, j: &mut JsonWriter<W>) {
269 j.begin_obj();
270 let mut first = true;
271 for (name, anim) in &self.animations {
272 if !first {
273 j.comma();
274 }
275 first = false;
276 j.key(name);
277 anim.write_json(j);
278 }
279 j.end_obj();
280 }
281}
282
283impl Meta {
284 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
285 j.begin_obj();
286 j.key("name");
287 j.opt_str(self.name.as_deref());
288 j.comma();
289 j.key("version");
290 j.str_val(&self.version);
291 j.comma();
292 j.key("rigger");
293 j.opt_str(self.rigger.as_deref());
294 j.comma();
295 j.key("artist");
296 j.opt_str(self.artist.as_deref());
297 j.comma();
298 j.key("rights");
299 j.opt_str(self.rights.as_deref());
300 j.comma();
301 j.key("copyright");
302 j.opt_str(self.copyright.as_deref());
303 j.comma();
304 j.key("licenseURL");
305 j.opt_str(self.license_url.as_deref());
306 j.comma();
307 j.key("contact");
308 j.opt_str(self.contact.as_deref());
309 j.comma();
310 j.key("reference");
311 j.opt_str(self.reference.as_deref());
312 j.comma();
313 j.key("thumbnailId");
314 j.u32_val(self.thumbnail_id);
315 j.comma();
316 j.key("preservePixels");
317 j.bool_val(self.preserve_pixels);
318 j.end_obj();
319 }
320}
321
322impl Physics {
323 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
324 j.begin_obj();
325 j.key("pixelsPerMeter");
326 j.f32_val(self.pixels_per_meter);
327 j.comma();
328 j.key("gravity");
329 j.f32_val(self.gravity);
330 j.end_obj();
331 }
332}
333
334impl Node {
335 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
336 j.begin_obj();
337 j.key("uuid");
338 j.u32_val(self.uuid);
339 j.comma();
340 j.key("name");
341 j.str_val(&self.name);
342 j.comma();
343 j.key("type");
344 j.str_val(self.type_node.type_str());
345 j.comma();
346 j.key("enabled");
347 j.bool_val(self.enabled);
348 j.comma();
349 j.key("zsort");
350 j.f32_val(self.zsort);
351 j.comma();
352 j.key("transform");
353 self.transform.write_json(j);
354 j.comma();
355 j.key("lockToRoot");
356 j.bool_val(self.lock_to_root);
357
358 self.type_node.write_fields(j);
359
360 if !self.children.is_empty() {
361 j.comma();
362 j.key("children");
363 j.begin_arr();
364 for (i, child) in self.children.iter().enumerate() {
365 if i > 0 {
366 j.comma();
367 }
368 child.write_json(j);
369 }
370 j.end_arr();
371 }
372
373 j.end_obj();
374 }
375}
376
377impl Transform {
378 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
379 j.begin_obj();
380 j.key("trans");
381 j.vec3(self.translation);
382 j.comma();
383 j.key("rot");
384 j.vec3(self.rotation);
385 j.comma();
386 j.key("scale");
387 j.vec2(self.scale);
388 j.end_obj();
389 }
390}
391
392impl NodeDataType {
393 fn type_str(&self) -> &'static str {
394 match self {
395 Self::Part(_) => "Part",
396 Self::Camera(_) => "Camera",
397 Self::SimplePhysics(_) => "SimplePhysics",
398 Self::Composite(_) => "Composite",
399 Self::Mask(_) => "Mask",
400 Self::MeshGroup(_) => "MeshGroup",
401 Self::Generic => "Node",
402 }
403 }
404
405 fn write_fields<W: Write>(&self, j: &mut JsonWriter<W>) {
406 match self {
407 Self::Part(d) => d.write_fields(j),
408 Self::Camera(d) => d.write_fields(j),
409 Self::SimplePhysics(d) => d.write_fields(j),
410 Self::Composite(d) => d.write_fields(j),
411 Self::Mask(d) => d.write_fields(j),
412 Self::MeshGroup(d) => d.write_fields(j),
413 Self::Generic => {}
414 }
415 }
416}
417
418impl PartData {
419 fn write_fields<W: Write>(&self, j: &mut JsonWriter<W>) {
420 j.comma();
421 j.key("mesh");
422 write_mesh(j, self.mesh.as_ref());
423 j.comma();
424 j.key("textures");
425 j.begin_arr();
426 j.u32_val(self.textures[0]);
427 j.comma();
428 j.u32_val(self.textures[1]);
429 j.comma();
430 j.u32_val(self.textures[2]);
431 j.end_arr();
432 j.comma();
433 j.key("blend_mode");
434 j.str_val(blend_mode_str(self.blend_mode));
435 j.comma();
436 j.key("tint");
437 j.vec3(self.tint);
438 j.comma();
439 j.key("screenTint");
440 j.vec3(self.screen_tint);
441 j.comma();
442 j.key("emissionStrength");
443 j.f32_val(self.emission_strength);
444 if !self.mask.is_empty() {
445 j.comma();
446 j.key("masks");
447 j.begin_arr();
448 for (i, m) in self.mask.iter().enumerate() {
449 if i > 0 {
450 j.comma();
451 }
452 m.write_json(j);
453 }
454 j.end_arr();
455 }
456 j.comma();
457 j.key("mask_threshold");
458 j.f32_val(self.mask_threshold);
459 j.comma();
460 j.key("opacity");
461 j.f32_val(self.opacity);
462 if let Some(ref path) = self.psd_layer_path {
463 j.comma();
464 j.key("psdLayerPath");
465 j.str_val(path);
466 }
467 }
468}
469
470impl CameraData {
471 fn write_fields<W: Write>(&self, j: &mut JsonWriter<W>) {
472 j.comma();
473 j.key("viewport");
474 j.vec2(self.viewport);
475 }
476}
477
478impl SimplePhysicsData {
479 fn write_fields<W: Write>(&self, j: &mut JsonWriter<W>) {
480 j.comma();
481 j.key("param");
482 j.u32_val(self.param);
483 j.comma();
484 j.key("model_type");
485 j.str_val(match self.model_type {
486 PhysicsModelType::Pendulum => "Pendulum",
487 PhysicsModelType::SpringPendulum => "SpringPendulum",
488 });
489 j.comma();
490 j.key("map_mode");
491 j.str_val(match self.map_mode {
492 PhysicsMapMode::AngleLength => "AngleLength",
493 PhysicsMapMode::XY => "XY",
494 PhysicsMapMode::LengthAngle => "LengthAngle",
495 PhysicsMapMode::YX => "YX",
496 });
497 j.comma();
498 j.key("gravity");
499 j.f32_val(self.gravity);
500 j.comma();
501 j.key("length");
502 j.f32_val(self.length);
503 j.comma();
504 j.key("frequency");
505 j.f32_val(self.frequency);
506 j.comma();
507 j.key("angle_damping");
508 j.f32_val(self.angle_damping);
509 j.comma();
510 j.key("length_damping");
511 j.f32_val(self.length_damping);
512 j.comma();
513 j.key("output_scale");
514 j.vec2(self.output_scale);
515 if let Some(lo) = self.local_only {
516 j.comma();
517 j.key("local_only");
518 j.bool_val(lo);
519 }
520 }
521}
522
523impl CompositeData {
524 fn write_fields<W: Write>(&self, j: &mut JsonWriter<W>) {
525 j.comma();
526 j.key("blend_mode");
527 j.str_val(blend_mode_str(self.blend_mode));
528 j.comma();
529 j.key("tint");
530 j.vec3(self.tint);
531 j.comma();
532 j.key("screenTint");
533 j.vec3(self.screen_tint);
534 j.comma();
535 j.key("opacity");
536 j.f32_val(self.opacity);
537 if !self.mask.is_empty() {
538 j.comma();
539 j.key("masks");
540 j.begin_arr();
541 for (i, m) in self.mask.iter().enumerate() {
542 if i > 0 {
543 j.comma();
544 }
545 m.write_json(j);
546 }
547 j.end_arr();
548 }
549 j.comma();
550 j.key("mask_threshold");
551 j.f32_val(self.mask_threshold);
552 if let Some(p) = self.propagate_meshgroup {
553 j.comma();
554 j.key("propagate_meshgroup");
555 j.bool_val(p);
556 }
557 }
558}
559
560impl MaskData {
561 fn write_fields<W: Write>(&self, j: &mut JsonWriter<W>) {
562 j.comma();
563 j.key("mesh");
564 write_mesh(j, self.mesh.as_ref());
565 }
566}
567
568impl MeshGroupData {
569 fn write_fields<W: Write>(&self, j: &mut JsonWriter<W>) {
570 j.comma();
571 j.key("mesh");
572 write_mesh(j, self.mesh.as_ref());
573 j.comma();
574 j.key("dynamic_deformation");
575 j.bool_val(self.dynamic_deformation);
576 j.comma();
577 j.key("translate_children");
578 j.bool_val(self.translate_children);
579 }
580}
581
582impl Mask {
583 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
584 j.begin_obj();
585 j.key("source");
586 j.u32_val(self.source);
587 j.comma();
588 j.key("mode");
589 j.str_val(match self.mode {
590 MaskMode::Mask => "Mask",
591 MaskMode::Dodge => "DodgeMask",
592 });
593 j.end_obj();
594 }
595}
596
597impl Param {
598 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
599 j.begin_obj();
600 if let Some(parent) = self.parent_uuid {
601 j.key("parentUUID");
602 j.u32_val(parent);
603 j.comma();
604 }
605 j.key("uuid");
606 j.u32_val(self.uuid);
607 j.comma();
608 j.key("name");
609 j.str_val(&self.name);
610 j.comma();
611 j.key("is_vec2");
612 j.bool_val(self.is_vec2);
613 j.comma();
614 j.key("min");
615 j.vec2(self.min);
616 j.comma();
617 j.key("max");
618 j.vec2(self.max);
619 j.comma();
620 j.key("defaults");
621 j.vec2(self.defaults);
622 j.comma();
623 j.key("axis_points");
624 j.begin_arr();
625 j.f32_arr(&self.axis_points[0]);
626 j.comma();
627 j.f32_arr(&self.axis_points[1]);
628 j.end_arr();
629 j.comma();
630 j.key("merge_mode");
631 j.str_val(merge_mode_str(self.merge_mode));
632 j.comma();
633 j.key("bindings");
634 j.begin_arr();
635 for (i, b) in self.bindings.iter().enumerate() {
636 if i > 0 {
637 j.comma();
638 }
639 b.write_json(j);
640 }
641 j.end_arr();
642 j.end_obj();
643 }
644}
645
646impl ParamBinding {
647 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
648 j.begin_obj();
649 j.key("node");
650 j.u32_val(self.node);
651 j.comma();
652 j.key("param_name");
653 j.str_val(param_name_str(&self.param_name));
654 j.comma();
655 j.key("interpolate_mode");
656 j.str_val(interpolation_str(self.interpolate_mode));
657 j.comma();
658 j.key("isSet");
659 j.begin_arr();
660 for (i, row) in self.is_set.iter().enumerate() {
661 if i > 0 {
662 j.comma();
663 }
664 j.begin_arr();
665 for (k, &b) in row.iter().enumerate() {
666 if k > 0 {
667 j.comma();
668 }
669 j.bool_val(b);
670 }
671 j.end_arr();
672 }
673 j.end_arr();
674 j.comma();
675 j.key("values");
676 self.write_values(j);
677 j.end_obj();
678 }
679
680 fn write_values<W: Write>(&self, j: &mut JsonWriter<W>) {
681 match &self.values {
682 BindingValues::Transform(flat) => flat.write_json(j),
683 BindingValues::Deform(flat) => {
684 let x_count = self.is_set.len().max(1);
685 let y_count = self.is_set.first().map(|r| r.len()).unwrap_or(1).max(1);
686 flat.write_json_shaped(j, x_count, y_count);
687 }
688 BindingValues::Other(v) => j.json_value(v),
689 }
690 }
691}
692
693impl FlatTransformValues {
694 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
695 j.begin_arr();
696 for f in 0..self.frames {
697 if f > 0 {
698 j.comma();
699 }
700 j.begin_arr();
701 let start = f * self.values_per_frame;
702 for k in 0..self.values_per_frame {
703 if k > 0 {
704 j.comma();
705 }
706 j.f32_val(self.data[start + k]);
707 }
708 j.end_arr();
709 }
710 j.end_arr();
711 }
712}
713
714impl FlatDeformValues {
715 fn write_json_shaped<W: Write>(&self, j: &mut JsonWriter<W>, x_count: usize, y_count: usize) {
716 let actual_vtx = if y_count > 0 {
723 self.vertices_per_frame / y_count
724 } else {
725 self.vertices_per_frame
726 };
727
728 j.begin_arr();
729 for x in 0..x_count {
730 if x > 0 {
731 j.comma();
732 }
733 j.begin_arr();
734 for y in 0..y_count {
735 if y > 0 {
736 j.comma();
737 }
738 j.begin_arr();
739 for v in 0..actual_vtx {
740 if v > 0 {
741 j.comma();
742 }
743 let idx = x * self.vertices_per_frame + y * actual_vtx + v;
744 let [dx, dy] = self.data.get(idx).copied().unwrap_or([0.0, 0.0]);
745 j.begin_arr();
746 j.f32_val(dx);
747 j.comma();
748 j.f32_val(dy);
749 j.end_arr();
750 }
751 j.end_arr();
752 }
753 j.end_arr();
754 }
755 j.end_arr();
756 }
757}
758
759impl Animation {
760 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
761 j.begin_obj();
762 j.key("timestep");
763 j.f32_val(self.timestep);
764 j.comma();
765 j.key("additive");
766 j.bool_val(self.additive);
767 j.comma();
768 j.key("length");
769 j.u32_val(self.length);
770 j.comma();
771 j.key("leadIn");
772 j.u32_val(self.lead_in);
773 j.comma();
774 j.key("leadOut");
775 j.u32_val(self.lead_out);
776 j.comma();
777 j.key("animationWeight");
778 j.f32_val(self.weight);
779 j.comma();
780 j.key("lanes");
781 j.begin_arr();
782 for (i, lane) in self.lanes.iter().enumerate() {
783 if i > 0 {
784 j.comma();
785 }
786 lane.write_json(j);
787 }
788 j.end_arr();
789 j.end_obj();
790 }
791}
792
793impl AnimationLane {
794 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
795 j.begin_obj();
796 j.key("interpolation");
797 j.str_val(interpolation_str(self.interpolation));
798 j.comma();
799 j.key("uuid");
800 j.u32_val(self.param_uuid);
801 j.comma();
802 j.key("target");
803 j.u32_val(self.target as u32);
804 j.comma();
805 j.key("merge_mode");
806 j.str_val(merge_mode_str(self.merge_mode));
807 j.comma();
808 j.key("keyframes");
809 j.begin_arr();
810 for (i, kf) in self.keyframes.iter().enumerate() {
811 if i > 0 {
812 j.comma();
813 }
814 kf.write_json(j);
815 }
816 j.end_arr();
817 j.end_obj();
818 }
819}
820
821impl Keyframe {
822 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
823 j.begin_obj();
824 j.key("frame");
825 j.u32_val(self.frame);
826 j.comma();
827 j.key("value");
828 j.f32_val(self.value);
829 j.comma();
830 j.key("tension");
831 j.f32_val(self.tension);
832 j.end_obj();
833 }
834}
835
836impl Group {
837 fn write_json<W: Write>(&self, j: &mut JsonWriter<W>) {
838 j.begin_obj();
839 j.key("groupUUID");
840 j.u32_val(self.group_uuid);
841 j.comma();
842 j.key("name");
843 j.str_val(&self.name);
844 j.comma();
845 j.key("color");
846 j.vec3(self.color);
847 j.end_obj();
848 }
849}
850
851fn write_mesh<W: Write>(j: &mut JsonWriter<W>, mesh: Option<&Mesh>) {
852 match mesh {
853 Some(m) => {
854 j.begin_obj();
855 j.key("verts");
856 j.f32_arr(&m.vertices);
857 j.comma();
858 j.key("indices");
859 j.begin_arr();
860 for (i, &idx) in m.indices.iter().enumerate() {
861 if i > 0 {
862 j.comma();
863 }
864 j.u32_val(idx);
865 }
866 j.end_arr();
867 j.comma();
868 j.key("uvs");
869 j.f32_arr(&m.uvs);
870 j.comma();
871 j.key("origin");
872 j.vec2(m.origin);
873 j.end_obj();
874 }
875 None => {
876 j.begin_obj();
878 j.key("verts");
879 j.begin_arr();
880 j.end_arr();
881 j.comma();
882 j.key("indices");
883 j.null();
884 j.comma();
885 j.key("origin");
886 j.vec2([0.0, 0.0]);
887 j.end_obj();
888 }
889 }
890}
891
892fn blend_mode_str(bm: BlendMode) -> &'static str {
893 match bm {
894 BlendMode::Normal => "Normal",
895 BlendMode::Multiply => "Multiply",
896 BlendMode::Screen => "Screen",
897 BlendMode::Overlay => "Overlay",
898 BlendMode::Darken => "Darken",
899 BlendMode::Lighten => "Lighten",
900 BlendMode::ColorDodge => "ColorDodge",
901 BlendMode::LinearDodge => "LinearDodge",
902 BlendMode::Add => "Add",
903 BlendMode::ColorBurn => "ColorBurn",
904 BlendMode::HardLight => "HardLight",
905 BlendMode::SoftLight => "SoftLight",
906 BlendMode::Subtract => "Subtract",
907 BlendMode::Difference => "Difference",
908 BlendMode::Exclusion => "Exclusion",
909 BlendMode::Inverse => "Inverse",
910 BlendMode::DestinationIn => "DestinationIn",
911 BlendMode::ClipToLower => "ClipToLower",
912 BlendMode::SliceFromLower => "SliceFromLower",
913 }
914}
915
916fn merge_mode_str(mm: MergeMode) -> &'static str {
917 match mm {
918 MergeMode::Additive => "Additive",
919 MergeMode::Multiplicative => "Multiply",
920 MergeMode::Override => "Override",
921 MergeMode::Forced => "Forced",
922 }
923}
924
925fn interpolation_str(i: Interpolation) -> &'static str {
926 match i {
927 Interpolation::Linear => "Linear",
928 Interpolation::Stepped => "Stepped",
929 Interpolation::Nearest => "Nearest",
930 Interpolation::Cubic => "Cubic",
931 }
932}
933
934fn param_name_str(pn: &ParamName) -> &str {
935 match pn {
936 ParamName::TransformTX => "transform.t.x",
937 ParamName::TransformTY => "transform.t.y",
938 ParamName::TransformTZ => "transform.t.z",
939 ParamName::TransformSX => "transform.s.x",
940 ParamName::TransformSY => "transform.s.y",
941 ParamName::TransformRX => "transform.r.x",
942 ParamName::TransformRY => "transform.r.y",
943 ParamName::TransformRZ => "transform.r.z",
944 ParamName::Deform => "deform",
945 ParamName::Opacity => "opacity",
946 ParamName::Other(s) => s.as_str(),
947 }
948}