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
use super::data::{Environment, Level};
use lu_formats::files::lvl::{
    parse_chunk, parse_editor_settings, parse_environment_data, parse_fib_data,
    parse_lighting_info, parse_lvl, parse_object_data, parse_particle_data, parse_skydome_info,
    ChunkType, FibData, ObjectInfo, Particle,
};
use nom::Finish;

fn parse_environment<'a>(bytes: &'a [u8], fib_data: &FibData) -> Option<Environment<'a>> {
    if fib_data.ofs_environment_chunk == 0 {
        return None;
    }
    let env_chunk_bytes = &bytes[fib_data.ofs_environment_chunk as usize..];
    let (_, env_chunk) = parse_chunk(env_chunk_bytes)
        .finish()
        .expect("Failed to parse environment_chunk");
    assert_eq!(env_chunk.r#type, ChunkType::Environment);

    let env_bytes = &bytes[env_chunk.data_offset as usize..][..(env_chunk.size - 32) as usize];
    let (_, env) = parse_environment_data(env_bytes)
        .finish()
        .expect("Failed to parse environment_data");

    let lighting_bytes = &bytes[env.ofs_lighting as usize..];
    let (_, lighting_info) = parse_lighting_info(fib_data.version)(lighting_bytes)
        .finish()
        .expect("Failed to parse lighting_info");

    let skydome_bytes = &bytes[env.ofs_skydome as usize..];
    let (_, skydome_info) = parse_skydome_info(fib_data.version)(skydome_bytes)
        .finish()
        .expect("Failed to parse skydome_info");

    let editor_settings_bytes = &bytes[env.ofs_editor_settings as usize..];
    let (_, editor_settings) = parse_editor_settings(editor_settings_bytes)
        .finish()
        .expect("Failed to parse editor_settings");

    Some(Environment {
        lighting_info,
        skydome_info,
        editor_settings,
    })
}

fn parse_objects<'a>(bytes: &'a [u8], fib_data: &FibData) -> Option<Vec<ObjectInfo<'a>>> {
    if fib_data.ofs_object_chunk == 0 {
        return None;
    }
    let object_chunk_bytes = &bytes[fib_data.ofs_object_chunk as usize..];
    let (_, object_chunk) = parse_chunk(object_chunk_bytes)
        .finish()
        .expect("Failed to parse object_chunk");
    assert_eq!(object_chunk.r#type, ChunkType::Object);
    let object_bytes =
        &bytes[object_chunk.data_offset as usize..][..(object_chunk.size - 32) as usize];
    let (_, objects) = parse_object_data(fib_data.version)(object_bytes)
        .finish()
        .expect("Failed to parse object_data");
    Some(objects.objects)
}

fn parse_particles<'a>(bytes: &'a [u8], fib_data: &FibData) -> Option<Vec<Particle<'a>>> {
    if fib_data.ofs_particle_chunk == 0 {
        return None;
    }
    let chunk_bytes = &bytes[fib_data.ofs_particle_chunk as usize..];
    let (_, chunk) = parse_chunk(chunk_bytes)
        .finish()
        .expect("Failed to parse particle_chunk");
    assert_eq!(chunk.r#type, ChunkType::Particle);
    let particle_bytes = &bytes[chunk.data_offset as usize..][..(chunk.size - 32) as usize];
    let (_, particle_data) = parse_particle_data(fib_data.version)(particle_bytes)
        .finish()
        .expect("Failed to parse object_data");
    Some(particle_data.particles)
}

pub fn parse_level(bytes: &[u8]) -> Level<'_> {
    let (_, lvl) = parse_lvl(bytes).finish().expect("Failed to parse lvl");

    let fib_bytes =
        &bytes[lvl.fib_chunk.data_offset as usize..][..(lvl.fib_chunk.size - 32) as usize];
    let (_, fib_data) = parse_fib_data(fib_bytes)
        .finish()
        .expect("Failed to parse fib_data");

    let environment = parse_environment(bytes, &fib_data);
    let objects = parse_objects(bytes, &fib_data);
    let particles = parse_particles(bytes, &fib_data);
    Level {
        version: fib_data.version,
        revision: fib_data.revision,
        environment,
        objects,
        particles,
    }
}