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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
|
use ::map as mapfile;
use anyhow::Error;
use common::{num::Cast, pretty, vec};
use log::{info, log, warn};
use ndarray::Array2;
use std::{
collections::{hash_map, HashMap},
fs::File,
mem,
};
pub use mapfile::format;
pub use mapfile::{
format::Tile,
reader::{self, Color as BadColor, LayerTilemapType},
};
use super::helper::Color;
pub const TILE_NUM: u32 = 16;
pub struct Layer {
pub color: Color,
pub image: Option<usize>,
pub tiles: Array2<Tile>,
pub kind: LayerTilemapType,
}
pub struct Map {
pub layers: Vec<Layer>,
pub tilesets: HashMap<Option<usize>, Array2<Color>>,
}
impl Map {
pub fn empty() -> Self {
Self {
layers: Vec::new(),
tilesets: HashMap::new(),
}
}
pub fn load(file: File) -> Result<Self, Error> {
info!("loading map");
let datafile = datafile::Reader::new(file).unwrap();
let mut map = mapfile::Reader::from_datafile(datafile);
let mut layers = vec![];
for group_idx in map.group_indices() {
let group = map.group(group_idx).unwrap();
if group.parallax_x != 100
|| group.parallax_y != 100
|| group.offset_x != 0
|| group.offset_y != 0
|| group.clipping.is_some()
{
warn!(
"skipping layer: {}: off_x:{} off_y:{} parallax_x:{} parallax_y:{} clipping:{:?}",
pretty::AlmostString::new(&group.name),
group.offset_x,
group.offset_y,
group.parallax_x,
group.parallax_y,
group.clipping,
);
continue;
}
for layer_idx in group.layer_indices {
let layer = map.layer(layer_idx).unwrap();
let tilemap = if let reader::LayerType::Tilemap(t) = layer.t {
t
} else {
continue;
};
let normal = if let Some(n) = tilemap.type_.to_normal() {
n
} else {
continue;
};
let tiles = map.layer_tiles(tilemap.tiles(normal.data)).unwrap();
layers.push(Layer {
color: Color {
r: normal.color.red,
g: normal.color.green,
b: normal.color.blue,
a: normal.color.alpha,
},
image: normal.image,
kind: tilemap.type_,
tiles,
});
}
}
let mut tilesets = HashMap::new();
for layer in &layers {
match tilesets.entry(layer.image) {
hash_map::Entry::Occupied(_) => {}
hash_map::Entry::Vacant(v) => {
let data = match layer.image {
None => Array2::from_elem(
(1, 1),
Color {
a: 255,
r: 255,
g: 0,
b: 255,
},
),
Some(image_idx) => {
let image = map.image(image_idx).unwrap();
let height = image.height.usize();
let width = image.width.usize();
match image.data {
Some(d) => {
let data = map.image_data(d).unwrap();
if data.len() % mem::size_of::<Color>() != 0 {
panic!("image shape invalid");
}
let data: Vec<Color> = unsafe { vec::transmute(data) };
Array2::from_shape_vec((height, width), data).unwrap()
}
None => {
warn!("layer with external tileset skipped");
continue;
// let image_name = map.image_name(image.name)?;
// // WARN? Unknown external image
// // WARN! Wrong dimensions
// str::from_utf8(&image_name).ok()
// .and_then(sanitize)
// .map(&mut external_tileset_loader)
// .transpose()?
// .unwrap_or(None)
// .unwrap_or_else(|| Array2::from_elem((1, 1), Color::white()))
}
}
}
};
v.insert(data);
}
}
}
info!(
"{} layers + {} tilesets loaded",
layers.len(),
tilesets.len()
);
Ok(Self { tilesets, layers })
}
}
|