Skip to content

Commit 375f822

Browse files
committed
Support variable terrain count
1 parent c22bb8c commit 375f822

File tree

8 files changed

+80
-71
lines changed

8 files changed

+80
-71
lines changed

.github/workflows/continuous-integration.yml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
name: Build
2-
# This workflow is triggered on pushes to the repository.
32
on:
43
pull_request:
54
branches:
@@ -9,17 +8,15 @@ jobs:
98
test_Linux:
109
runs-on: ubuntu-latest
1110
steps:
12-
- uses: actions/checkout@v1
11+
- uses: actions/checkout@v2
1312
- name: Prepare
1413
run: rustc --version
15-
- name: Build
1614
run: cargo check
17-
- name: Test
1815
run: cargo test
1916
test_macOS:
2017
runs-on: macOS-latest
2118
steps:
22-
- uses: actions/checkout@v1
19+
- uses: actions/checkout@v2
2320
- name: Prepare
2421
run: |
2522
brew install rustup
@@ -35,10 +32,8 @@ jobs:
3532
test_Windows:
3633
runs-on: windows-latest
3734
steps:
38-
- uses: actions/checkout@v1
35+
- uses: actions/checkout@v2
3936
- name: Prepare
4037
run: rustc --version
41-
- name: Build
4238
run: cargo check
43-
- name: Test
4439
run: cargo test

Cargo.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/convert/layers.rs

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use vangers::level::{
2-
Level, LevelData, DELTA_MASK, DELTA_SHIFT0, DELTA_SHIFT1, DOUBLE_LEVEL, NUM_TERRAINS,
3-
TERRAIN_SHIFT,
2+
Level, LevelData, TerrainBits, DELTA_MASK, DELTA_SHIFT0, DELTA_SHIFT1, DOUBLE_LEVEL,
43
};
54

65
fn avg(a: u8, b: u8) -> u8 {
@@ -17,6 +16,7 @@ pub fn extract_palette(level: &Level) -> Vec<u8> {
1716

1817
pub struct LevelLayers {
1918
pub size: (u32, u32),
19+
pub num_terrains: u8,
2020
pub het0: Vec<u8>,
2121
pub het1: Vec<u8>,
2222
pub delta: Vec<u8>,
@@ -25,10 +25,11 @@ pub struct LevelLayers {
2525
}
2626

2727
impl LevelLayers {
28-
pub fn new(size: (u32, u32)) -> Self {
28+
pub fn new(size: (u32, u32), num_terrains: u8) -> Self {
2929
let total = (size.0 * size.1) as usize;
3030
LevelLayers {
3131
size,
32+
num_terrains,
3233
het0: Vec::with_capacity(total),
3334
het1: Vec::with_capacity(total),
3435
delta: Vec::with_capacity(total),
@@ -37,13 +38,14 @@ impl LevelLayers {
3738
}
3839
}
3940

40-
pub fn from_level_data(data: &LevelData) -> Self {
41-
let mut ll = LevelLayers::new((data.size.0 as u32, data.size.1 as u32));
41+
pub fn from_level_data(data: &LevelData, num_terrains: u8) -> Self {
42+
let mut ll = LevelLayers::new((data.size.0 as u32, data.size.1 as u32), num_terrains);
4243
ll.import(data);
4344
ll
4445
}
4546

4647
fn import(&mut self, data: &LevelData) {
48+
let terrain_bits = TerrainBits::new(self.num_terrains);
4749
for y in 0..data.size.1 as usize {
4850
let range = y * data.size.0 as usize..(y + 1) * data.size.0 as usize;
4951
let hrow = &data.height[range.clone()];
@@ -54,8 +56,8 @@ impl LevelLayers {
5456
.zip(hrow[1..].iter().step_by(2))
5557
.zip(mrow.iter().step_by(2).zip(mrow[1..].iter().step_by(2)))
5658
{
57-
let t0 = (m0 >> TERRAIN_SHIFT) & (NUM_TERRAINS as u8 - 1);
58-
let t1 = (m1 >> TERRAIN_SHIFT) & (NUM_TERRAINS as u8 - 1);
59+
let t0 = terrain_bits.read(m0);
60+
let t1 = terrain_bits.read(m1);
5961
if m0 & DOUBLE_LEVEL != 0 {
6062
let d =
6163
((m0 & DELTA_MASK) << DELTA_SHIFT0) + ((m1 & DELTA_MASK) << DELTA_SHIFT1);
@@ -83,6 +85,7 @@ impl LevelLayers {
8385
}
8486

8587
pub fn export(self) -> LevelData {
88+
let terrain_shift = TerrainBits::new(self.num_terrains).shift;
8689
let total = self.size.0 as usize * self.size.1 as usize;
8790
let mut height = Vec::with_capacity(total);
8891
let mut meta = Vec::with_capacity(total);
@@ -110,16 +113,16 @@ impl LevelLayers {
110113
let delta = avg(da, db);
111114
if delta != 0 {
112115
//Note: mat0b and mat1a are ignored here, assuming the same as mat0a and mat1b respectively
113-
meta.push(DOUBLE_LEVEL | ((mat0 & 0xF) << TERRAIN_SHIFT) | (delta >> 2));
114-
meta.push(DOUBLE_LEVEL | ((mat1 >> 4) << TERRAIN_SHIFT) | (delta & DELTA_MASK));
116+
meta.push(DOUBLE_LEVEL | ((mat0 & 0xF) << terrain_shift) | (delta >> 2));
117+
meta.push(DOUBLE_LEVEL | ((mat1 >> 4) << terrain_shift) | (delta & DELTA_MASK));
115118
height.push(avg(h0a, h0b));
116119
height.push(avg(h1a, h1b));
117120
} else {
118121
//Note: mat1 and deltas are ignored here, assuming mat0 == mat1
119122
height.push(avg(h0a, h1a));
120123
height.push(avg(h0b, h1b));
121-
meta.push((mat0 & 0xF) << TERRAIN_SHIFT);
122-
meta.push((mat0 >> 4) << TERRAIN_SHIFT);
124+
meta.push((mat0 & 0xF) << terrain_shift);
125+
meta.push((mat0 >> 4) << terrain_shift);
123126
}
124127
}
125128

bin/convert/level_png.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use std::{fs::File, path::PathBuf};
99
struct MultiPng {
1010
size: (u32, u32),
1111
height: String,
12+
num_terrains: u8,
1213
material_lo: String,
1314
material_hi: String,
1415
}
@@ -19,6 +20,7 @@ pub fn save(path: &PathBuf, layers: LevelLayers, palette: &[u8]) {
1920
let mp = MultiPng {
2021
size: layers.size,
2122
height: "height.png".to_string(),
23+
num_terrains: layers.num_terrains,
2224
material_lo: "material_lo.png".to_string(),
2325
material_hi: "material_hi.png".to_string(),
2426
};
@@ -73,7 +75,7 @@ pub fn save(path: &PathBuf, layers: LevelLayers, palette: &[u8]) {
7375
pub fn load(path: &PathBuf) -> LevelLayers {
7476
let level_file = File::open(path).unwrap();
7577
let mp = ron::de::from_reader::<_, MultiPng>(level_file).unwrap();
76-
let mut layers = LevelLayers::new(mp.size);
78+
let mut layers = LevelLayers::new(mp.size, mp.num_terrains);
7779
{
7880
println!("\t\t{}...", mp.height);
7981
let file = File::open(path.with_file_name(mp.height)).unwrap();

bin/convert/main.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,21 @@ fn main() {
100100
let config = vangers::level::LevelConfig::load(&src_path);
101101
let level = vangers::level::load(&config);
102102
let palette = layers::extract_palette(&level);
103-
let layers =
104-
layers::LevelLayers::from_level_data(&vangers::level::LevelData::from(level));
103+
let layers = layers::LevelLayers::from_level_data(
104+
&vangers::level::LevelData::from(level),
105+
config.terrains.len() as u8,
106+
);
105107
println!("\tSaving multiple PNGs...");
106108
level_png::save(&dst_path, layers, &palette);
107109
}
108110
("ini", "tiff") => {
109111
println!("\tLoading the level...");
110112
let config = vangers::level::LevelConfig::load(&src_path);
111113
let level = vangers::level::load(&config);
112-
let layers =
113-
layers::LevelLayers::from_level_data(&vangers::level::LevelData::from(level));
114+
let layers = layers::LevelLayers::from_level_data(
115+
&vangers::level::LevelData::from(level),
116+
config.terrains.len() as u8,
117+
);
114118
println!("\tSaving TIFF layers...");
115119
save_tiff(&dst_path, layers);
116120
}

src/level/config.rs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use super::NUM_TERRAINS;
2-
31
use ini::Ini;
42
use std::ops::Range;
53
use std::path::PathBuf;
@@ -30,7 +28,7 @@ pub struct LevelConfig {
3028
pub geo: Power,
3129
pub section: Power,
3230
pub min_square: Power,
33-
pub terrains: [TerrainConfig; NUM_TERRAINS],
31+
pub terrains: Box<[TerrainConfig]>,
3432
}
3533

3634
impl LevelConfig {
@@ -43,21 +41,17 @@ impl LevelConfig {
4341
let storage = &ini["Storage"];
4442
let render = &ini["Rendering Parameters"];
4543

46-
let tc = TerrainConfig {
47-
shadow_offset: 0,
48-
height_shift: 0,
49-
colors: 0..0,
50-
};
51-
let mut terrains = [
52-
tc.clone(),
53-
tc.clone(),
54-
tc.clone(),
55-
tc.clone(),
56-
tc.clone(),
57-
tc.clone(),
58-
tc.clone(),
59-
tc.clone(),
60-
];
44+
let terra_count = render
45+
.get("Terrain Max")
46+
.map_or(8, |value| value.parse::<usize>().unwrap());
47+
let mut terrains = (0..terra_count)
48+
.map(|_| TerrainConfig {
49+
shadow_offset: 0,
50+
height_shift: 0,
51+
colors: 0..0,
52+
})
53+
.collect::<Box<[_]>>();
54+
6155
for (t, val) in terrains
6256
.iter_mut()
6357
.zip(render["Shadow Offsets"].split_whitespace())

src/level/mod.rs

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,13 @@ mod config;
1010
pub use self::config::{LevelConfig, TerrainConfig};
1111

1212
pub type TerrainType = u8;
13-
pub const NUM_TERRAINS: usize = 8;
1413

1514
pub type Altitude = u8;
1615
pub type Delta = Altitude;
1716
pub const DOUBLE_LEVEL: u8 = 1 << 6;
1817
pub const DELTA_SHIFT0: u8 = 2 + 3;
1918
pub const DELTA_SHIFT1: u8 = 0 + 3;
2019
pub const DELTA_MASK: u8 = 0x3;
21-
pub const TERRAIN_SHIFT: u8 = 3;
2220
pub const HEIGHT_SCALE: u32 = 128;
2321

2422
pub struct Level {
@@ -28,11 +26,36 @@ pub struct Level {
2826
pub height: Vec<u8>,
2927
pub meta: Vec<u8>,
3028
pub palette: [[u8; 4]; 0x100],
31-
pub terrains: [TerrainConfig; NUM_TERRAINS],
29+
pub terrains: Box<[TerrainConfig]>,
3230
}
3331

3432
pub struct Point(pub Altitude, pub TerrainType);
3533

34+
pub struct TerrainBits {
35+
pub shift: u8,
36+
pub mask: TerrainType,
37+
}
38+
39+
impl TerrainBits {
40+
pub fn new(count: u8) -> Self {
41+
match count {
42+
8 => TerrainBits {
43+
shift: 3,
44+
mask: 0x7,
45+
},
46+
16 => TerrainBits {
47+
shift: 2,
48+
mask: 0xF,
49+
},
50+
other => panic!("Unexpected terrain count {}!", other),
51+
}
52+
}
53+
54+
pub fn read(&self, meta: u8) -> TerrainType {
55+
(meta >> self.shift) & self.mask
56+
}
57+
}
58+
3659
pub enum Texel {
3760
Single(Point),
3861
Dual {
@@ -65,24 +88,12 @@ impl Level {
6588
height: vec![0, 0],
6689
meta: vec![0, 0],
6790
palette: [[0xFF; 4]; 0x100],
68-
// not pretty, I know
69-
terrains: [
70-
tc.clone(),
71-
tc.clone(),
72-
tc.clone(),
73-
tc.clone(),
74-
tc.clone(),
75-
tc.clone(),
76-
tc.clone(),
77-
tc.clone(),
78-
],
91+
terrains: (0..8).map(|_| tc.clone()).collect(),
7992
}
8093
}
8194

8295
pub fn get(&self, mut coord: (i32, i32)) -> Texel {
83-
fn get_terrain(meta: u8) -> TerrainType {
84-
(meta >> TERRAIN_SHIFT) & (NUM_TERRAINS as u8 - 1)
85-
}
96+
let bits = TerrainBits::new(self.terrains.len() as u8);
8697
while coord.0 < 0 {
8798
coord.0 += self.size.0;
8899
}
@@ -97,12 +108,12 @@ impl Level {
97108
let d0 = (meta0 & DELTA_MASK) << DELTA_SHIFT0;
98109
let d1 = (meta1 & DELTA_MASK) << DELTA_SHIFT1;
99110
Texel::Dual {
100-
low: Point(self.height[i & !1], get_terrain(meta0)),
101-
high: Point(self.height[i | 1], get_terrain(meta1)),
111+
low: Point(self.height[i & !1], bits.read(meta0)),
112+
high: Point(self.height[i | 1], bits.read(meta1)),
102113
delta: d0 + d1,
103114
}
104115
} else {
105-
Texel::Single(Point(self.height[i], get_terrain(meta)))
116+
Texel::Single(Point(self.height[i], bits.read(meta)))
106117
}
107118
}
108119

@@ -281,7 +292,7 @@ impl LevelData {
281292
});
282293
}
283294

284-
pub fn import(data: &[u8], size: (i32, i32)) -> Self {
295+
pub fn import(data: &[u8], size: (i32, i32), terrain_shift: u8) -> Self {
285296
let total = (size.0 * size.1) as usize;
286297
assert_eq!(data.len(), total * 4);
287298
let mut level = LevelData {
@@ -300,15 +311,15 @@ impl LevelData {
300311
// average between two texels
301312
let mat = avg(color[3], color[7]);
302313
level.meta[i + 0] =
303-
DOUBLE_LEVEL | ((mat & 0xF) << TERRAIN_SHIFT) | (delta >> 2);
314+
DOUBLE_LEVEL | ((mat & 0xF) << terrain_shift) | (delta >> 2);
304315
level.meta[i + 1] =
305-
DOUBLE_LEVEL | ((mat >> 4) << TERRAIN_SHIFT) | (delta & DELTA_MASK);
316+
DOUBLE_LEVEL | ((mat >> 4) << terrain_shift) | (delta & DELTA_MASK);
306317
level.height[i + 0] = avg(color[0], color[4]);
307318
level.height[i + 1] = avg(color[1], color[5]);
308319
} else {
309320
// average between low and high
310-
level.meta[i + 0] = (color[3] & 0xF) << TERRAIN_SHIFT;
311-
level.meta[i + 1] = (color[7] & 0xF) << TERRAIN_SHIFT;
321+
level.meta[i + 0] = (color[3] & 0xF) << terrain_shift;
322+
level.meta[i + 1] = (color[7] & 0xF) << terrain_shift;
312323
level.height[i + 0] = avg(color[0], color[1]);
313324
level.height[i + 1] = avg(color[4], color[5]);
314325
}

src/render/terrain.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ impl Context {
475475
depth: 1,
476476
};
477477
let table_extent = wgpu::Extent3d {
478-
width: level::NUM_TERRAINS as u32,
478+
width: level.terrains.len() as u32,
479479
height: 1,
480480
depth: 1,
481481
};

0 commit comments

Comments
 (0)