# HG changeset patch # User Emmanuel Gil Peyrot # Date 1578351978 -3600 # Node ID 3555845f8cf4f025fe4f2881ac0ac41754e58cff # Parent 8d29dac12219c2af675dd52e0eae11d9d6499c5e Make it so we can use more than a single anm0 in an EclRunner. diff --git a/examples/stagerunner.rs b/examples/stagerunner.rs --- a/examples/stagerunner.rs +++ b/examples/stagerunner.rs @@ -92,24 +92,32 @@ fn main() { // Parse arguments. let args: Vec<_> = env::args().collect(); if args.len() != 4 { - eprintln!("Usage: {} ", args[0]); + eprintln!("Usage: {} ", args[0]); return; } - let ecl_filename = Path::new(&args[1]); - let anm_filename = Path::new(&args[2]); + let directory = Path::new(&args[1]); + let stage_number: u8 = args[2].parse().expect("stage"); let rank: Rank = args[3].parse().expect("rank"); // Open the ECL file. - let buf = load_file_into_vec(ecl_filename); + let buf = load_file_into_vec(directory.join(format!("ecldata{}.ecl", stage_number))); let (_, ecl) = Ecl::from_slice(&buf).unwrap(); assert_eq!(ecl.mains.len(), 1); let main = ecl.mains[0].clone(); // Open the ANM file. - let buf = load_file_into_vec(anm_filename); + let anm_filename = directory.join(format!("stg{}enm.anm", stage_number)); + let buf = load_file_into_vec(&anm_filename); let (_, mut anms) = Anm0::from_slice(&buf).unwrap(); let anm0 = anms.pop().unwrap(); - let anm0 = Rc::new(RefCell::new(anm0)); + + // Open the second ANM file. + let anm2_filename = directory.join(format!("stg{}enm2.anm", stage_number)); + let buf = load_file_into_vec(&anm2_filename); + let (_, mut anms) = Anm0::from_slice(&buf).unwrap(); + let anm0_bis = anms.pop().unwrap(); + + let anms = [anm0, anm0_bis]; // Get the time since January 1970 as a seed for the PRNG. let time = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap(); @@ -125,7 +133,15 @@ fn main() { let mut surface = GlfwSurface::new(WindowDim::Windowed(384, 448), "Touhou", WindowOpt::default()).unwrap(); // Open the image atlas matching this ANM. - let tex = load_anm_image(&mut surface, &anm0.borrow(), anm_filename).expect("image loading"); + let mut textures = vec![]; + for anm0 in anms.iter() { + let tex = load_anm_image(&mut surface, &anm0, &anm_filename).expect("image loading"); + textures.push(tex); + } + + let anms = Rc::new(RefCell::new(anms)); + let tex = textures.pop().unwrap(); + let tex = textures.pop().unwrap(); // set the uniform interface to our type so that we can read textures from the shader let program = @@ -171,7 +187,7 @@ fn main() { MainInstruction::SpawnEnemyMirroredRandom(x, y, z, life, bonus, score) => (x, y, z, life, bonus, score, true), _ => continue, }; - let enemy = Enemy::new(Position::new(x, y), life, bonus, score, mirror, Rc::downgrade(&anm0), Rc::downgrade(&game)); + let enemy = Enemy::new(Position::new(x, y), life, bonus, score, mirror, Rc::downgrade(&anms), Rc::downgrade(&game)); let runner = EclRunner::new(&ecl, enemy, sub); ecl_runners.push(runner); } diff --git a/src/th06/anm0_vm.rs b/src/th06/anm0_vm.rs --- a/src/th06/anm0_vm.rs +++ b/src/th06/anm0_vm.rs @@ -214,9 +214,50 @@ impl Sprite { } } +struct Anms { + inner: Rc>, +} + +impl Anms { + fn new(anms: Rc>) -> Anms { + Anms { + inner: anms, + } + } + + fn load_sprite(&self, sprite: &mut Sprite, id: u8) { + let anms = self.inner.borrow(); + let mut anm = None; + let mut texcoords = None; + 'anm: for anm0 in anms.iter() { + for sp in anm0.sprites.iter() { + if sp.index == id as u32 { + texcoords = Some(sp); + anm = Some(anm0.clone()); + break 'anm; + } + } + } + sprite.anm = anm; + if let Some(texcoords) = texcoords { + sprite.texcoords = [texcoords.x, texcoords.y, texcoords.width, texcoords.height]; + } + } + + fn get_script(&self, id: u8) -> Script { + let anms = self.inner.borrow(); + for anm0 in anms.iter() { + if anm0.scripts.contains_key(&id) { + return anm0.scripts[&id].clone(); + } + } + unreachable!(); + } +} + /// Interpreter for `Anm0` instructions to update a `Sprite`. pub struct AnmRunner { - anm: Anm0, + anms: Anms, sprite: Rc>, prng: Weak>, running: bool, @@ -231,15 +272,17 @@ pub struct AnmRunner { impl AnmRunner { /// Create a new `AnmRunner`. - pub fn new(anm: &Anm0, script_id: u8, sprite: Rc>, prng: Weak>, sprite_index_offset: u32) -> AnmRunner { + pub fn new(anms: Rc>, script_id: u8, sprite: Rc>, prng: Weak>, sprite_index_offset: u32) -> AnmRunner { + let anms = Anms::new(anms); + let script = anms.get_script(script_id); let mut runner = AnmRunner { - anm: anm.clone(), + anms, sprite: sprite, prng, running: true, waiting: false, - script: anm.scripts[&script_id].clone(), + script, frame: 0, timeout: None, instruction_pointer: 0, @@ -321,9 +364,7 @@ impl AnmRunner { self.running = false; } Instruction::LoadSprite(sprite_index) => { - sprite.anm = Some(self.anm.clone()); - let texcoords = &self.anm.sprites[(sprite_index + self.sprite_index_offset) as usize]; - sprite.texcoords = [texcoords.x, texcoords.y, texcoords.width, texcoords.height]; + self.anms.load_sprite(&mut sprite, (sprite_index + self.sprite_index_offset) as u8); } Instruction::SetScale(sx, sy) => { sprite.rescale = [sx, sy]; @@ -375,11 +416,7 @@ impl AnmRunner { amplitude = (rand as u32) % amplitude; } let sprite_index = min_index + amplitude; - - // TODO: refactor that with Instruction::LoadSprite. - sprite.anm = Some(self.anm.clone()); - let texcoords = &self.anm.sprites[(sprite_index + self.sprite_index_offset) as usize]; - sprite.texcoords = [texcoords.x, texcoords.y, texcoords.width, texcoords.height]; + self.anms.load_sprite(&mut sprite, (sprite_index + self.sprite_index_offset) as u8); } Instruction::Move(x, y, z) => { sprite.dest_offset = [x, y, z]; diff --git a/src/th06/enemy.rs b/src/th06/enemy.rs --- a/src/th06/enemy.rs +++ b/src/th06/enemy.rs @@ -308,7 +308,7 @@ pub struct Enemy { pub(crate) speed_interpolator: Option>, // Misc stuff, do we need them? - pub(crate) anm0: Weak>, + pub(crate) anm0: Weak>, process: Rc>, pub(crate) game: Weak>, pub(crate) prng: Weak>, @@ -317,7 +317,7 @@ pub struct Enemy { impl Enemy { /// Create a new enemy. - pub fn new(pos: Position, life: i16, bonus_dropped: i16, die_score: u32, mirror: bool, anm0: Weak>, game: Weak>) -> Rc> { + pub fn new(pos: Position, life: i16, bonus_dropped: i16, die_score: u32, mirror: bool, anm0: Weak>, game: Weak>) -> Rc> { let game_rc = game.upgrade().unwrap(); let mut enemy = Enemy { pos, @@ -346,7 +346,7 @@ impl Enemy { let anm0 = self.anm0.upgrade().unwrap(); let game = self.game.upgrade().unwrap(); let sprite = Rc::new(RefCell::new(Sprite::new())); - let anmrunner = AnmRunner::new(&*anm0.borrow(), index, sprite, self.prng.clone(), 0); + let anmrunner = AnmRunner::new(anm0, index, sprite, self.prng.clone(), 0); let anmrunner = Rc::new(RefCell::new(anmrunner)); self.anmrunner = Rc::downgrade(&anmrunner); (*game.borrow_mut()).anmrunners.push(anmrunner); @@ -550,7 +550,15 @@ mod tests { file.read_to_end(&mut buf).unwrap(); let (_, mut anms) = Anm0::from_slice(&buf).unwrap(); let anm0 = anms.pop().unwrap(); - let anm0 = Rc::new(RefCell::new(anm0)); + + let file = File::open("EoSD/ST/stg1enm2.anm").unwrap(); + let mut file = io::BufReader::new(file); + let mut buf = vec![]; + file.read_to_end(&mut buf).unwrap(); + let (_, mut anms) = Anm0::from_slice(&buf).unwrap(); + let anm0_bis = anms.pop().unwrap(); + + let anm0 = Rc::new(RefCell::new([anm0, anm0_bis])); let prng = Rc::new(RefCell::new(Prng::new(0))); let game = Game::new(prng, Rank::EASY); let game = Rc::new(RefCell::new(game));