aboutsummaryrefslogtreecommitdiff
path: root/exporter/src/bin/gltf.rs
blob: fb6b72de6a7c0200263417c008d00ff5d96244ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#![feature(array_chunks)]
use anyhow::anyhow;
use glam::{Affine3A, Mat4};
use gltf::Glb;
use log::warn;
use std::{borrow::Cow, env::args, fs::File, io::BufReader};
use unity_tools::{
    classes::{
        gameobject::GameObject,
        mesh_renderer::{MeshRenderer, SkinnedMeshRenderer},
        transform::Transform,
    },
    serialized_file::SerializedFile,
    unityfs::UnityFS,
};

fn main() -> anyhow::Result<()> {
    env_logger::init_from_env("LOG");
    let file = || BufReader::new(File::open(args().nth(1).unwrap()).unwrap());
    let mut fs = UnityFS::open(file())?;

    let cabfile = fs
        .find_main_file()
        .ok_or(anyhow!("no CAB file found"))?
        .to_owned();

    let mut cab = fs.read(&cabfile)?;
    let mut file = SerializedFile::read(&mut cab)?;
    let gameobjects = file
        .objects
        .iter()
        .filter(|ob| file.get_object_type_tree(ob).unwrap().type_string == "GameObject")
        .cloned()
        .collect::<Vec<_>>();

    // let mut root_tr = Transform::from_value(file.read_object(ob)?)?;
    // while !root_tr.father.is_null() {
    //     root_tr = root_tr.father.load(&mut file)?;
    // }
    // eprintln!("{root_tr:?}");

    let mut root = gltf_json::Root::default();

    for ob in gameobjects {
        let go = file.read_object(ob)?.parse::<GameObject>()?;
        for comp in go.components {
            let ob = comp.load(&mut file)?;
            let mut global_transform = Affine3A::default();
            match ob.class_name().unwrap().as_str() {
                "Transform" => {
                    let mut tr = ob.parse::<Transform>()?;
                    let mut transforms = Vec::new();
                    loop {
                        transforms.push(
                            Mat4::from_translation(tr.local_position)
                                * Mat4::from_scale(tr.local_scale)
                                * Mat4::from_quat(tr.local_rotation),
                        );
                        if tr.father.is_null() {
                            break;
                        } else {
                            tr = tr.father.load(&mut file)?;
                        }
                    }
                    global_transform =
                        Affine3A::from_mat4(transforms.into_iter().reduce(|a, b| a * b).unwrap())
                }
                "SkinnedMeshRenderer" => {
                    let mr = ob.parse::<SkinnedMeshRenderer>()?;
                }
                "MeshRenderer" => {
                    let mr = ob.parse::<MeshRenderer>()?;
                }
                x => warn!("unknown component {x:?}"),
            }
        }
    }

    let json_string = gltf_json::serialize::to_string(&root).expect("Serialization error");
    let mut json_offset = json_string.len();
    align_to_multiple_of_four(&mut json_offset);
    let glb = Glb {
        header: gltf::binary::Header {
            magic: *b"glTF",
            version: 2,
            length: json_offset as u32,
        },
        bin: None,
        json: Cow::Owned(json_string.into_bytes()),
    };
    let writer = std::fs::File::create("triangle.glb").expect("I/O error");
    glb.to_writer(writer).expect("glTF binary output error");

    Ok(())
}

fn align_to_multiple_of_four(n: &mut usize) {
    *n = (*n + 3) & !3;
}