swf: Convert ButtonActionCondition to bitflags

This commit is contained in:
relrelb 2021-01-23 02:47:29 +02:00 committed by Mike Welsh
parent 7f4845d777
commit 19662503ca
6 changed files with 59 additions and 157 deletions

View File

@ -11,6 +11,7 @@ use gc_arena::{Collect, GcCell, MutationContext};
use std::collections::BTreeMap;
use std::convert::TryFrom;
use std::sync::Arc;
use swf::ButtonActionCondition;
#[derive(Clone, Debug, Collect, Copy)]
#[collect(no_drop)]
@ -42,15 +43,19 @@ impl<'gc> Button<'gc> {
let action_data = source_movie
.to_unbounded_subslice(action.action_data)
.unwrap();
for condition in &action.conditions {
let button_action = ButtonAction {
let bits = action.conditions.bits();
let mut bit = 1u16;
while bits & !(bit - 1) != 0 {
if bits & bit != 0 {
actions.push(ButtonAction {
action_data: action_data.clone(),
condition: *condition,
condition: ButtonActionCondition::from_bits_truncate(bit),
key_code: action
.key_code
.and_then(|k| ButtonKeyCode::try_from(k).ok()),
};
actions.push(button_action);
});
}
bit <<= 1;
}
}
@ -406,7 +411,7 @@ impl<'gc> TDisplayObject<'gc> for Button<'gc> {
ClipEvent::KeyPress { key_code } => {
handled = write.run_actions(
context,
swf::ButtonActionCondition::KeyPress,
swf::ButtonActionCondition::KEY_PRESS,
Some(key_code),
);
cur_state
@ -416,22 +421,30 @@ impl<'gc> TDisplayObject<'gc> for Button<'gc> {
match (cur_state, new_state) {
(ButtonState::Up, ButtonState::Over) => {
write.run_actions(context, swf::ButtonActionCondition::IdleToOverUp, None);
write.run_actions(context, swf::ButtonActionCondition::IDLE_TO_OVER_UP, None);
write.play_sound(context, write.static_data.read().up_to_over_sound.as_ref());
}
(ButtonState::Over, ButtonState::Up) => {
write.run_actions(context, swf::ButtonActionCondition::OverUpToIdle, None);
write.run_actions(context, swf::ButtonActionCondition::OVER_UP_TO_IDLE, None);
write.play_sound(context, write.static_data.read().over_to_up_sound.as_ref());
}
(ButtonState::Over, ButtonState::Down) => {
write.run_actions(context, swf::ButtonActionCondition::OverUpToOverDown, None);
write.run_actions(
context,
swf::ButtonActionCondition::OVER_UP_TO_OVER_DOWN,
None,
);
write.play_sound(
context,
write.static_data.read().over_to_down_sound.as_ref(),
);
}
(ButtonState::Down, ButtonState::Over) => {
write.run_actions(context, swf::ButtonActionCondition::OverDownToOverUp, None);
write.run_actions(
context,
swf::ButtonActionCondition::OVER_DOWN_TO_OVER_UP,
None,
);
write.play_sound(
context,
write.static_data.read().down_to_over_sound.as_ref(),
@ -512,7 +525,7 @@ impl<'gc> ButtonData<'gc> {
if let Some(parent) = self.base.parent {
for action in &self.static_data.read().actions {
if action.condition == condition
&& (action.condition != swf::ButtonActionCondition::KeyPress
&& (action.condition != swf::ButtonActionCondition::KEY_PRESS
|| action.key_code == key_code)
{
// Note that AVM1 buttons run actions relative to their parent, not themselves.

View File

@ -3108,10 +3108,10 @@ impl ClipAction {
.unwrap();
let mut events = Vec::new();
let flags = other.events.bits();
let bits = other.events.bits();
let mut bit = 1u32;
while flags & !(bit - 1) != 0 {
if (flags & bit) != 0 {
while bits & !(bit - 1) != 0 {
if bits & bit != 0 {
events.push(ClipEventFlag::from_bits_truncate(bit));
}
bit <<= 1;

View File

@ -13,7 +13,6 @@ use crate::{
};
use bitstream_io::BitRead;
use byteorder::{LittleEndian, ReadBytesExt};
use std::collections::HashSet;
use std::io::{self, Read};
/// Parse a decompressed SWF and return a `Vec` of tags.
@ -802,9 +801,7 @@ impl<'a> Reader<'a> {
is_track_as_menu: false,
records,
actions: vec![ButtonAction {
conditions: vec![ButtonActionCondition::OverDownToOverUp]
.into_iter()
.collect(),
conditions: ButtonActionCondition::OVER_DOWN_TO_OVER_UP,
key_code: None,
action_data,
}],
@ -937,39 +934,9 @@ impl<'a> Reader<'a> {
fn read_button_action(&mut self) -> Result<(ButtonAction<'a>, bool)> {
let length = self.read_u16()?;
let flags = self.read_u16()?;
let mut conditions = HashSet::with_capacity(8);
if (flags & 0b1) != 0 {
conditions.insert(ButtonActionCondition::IdleToOverUp);
}
if (flags & 0b10) != 0 {
conditions.insert(ButtonActionCondition::OverUpToIdle);
}
if (flags & 0b100) != 0 {
conditions.insert(ButtonActionCondition::OverUpToOverDown);
}
if (flags & 0b1000) != 0 {
conditions.insert(ButtonActionCondition::OverDownToOverUp);
}
if (flags & 0b1_0000) != 0 {
conditions.insert(ButtonActionCondition::OverDownToOutDown);
}
if (flags & 0b10_0000) != 0 {
conditions.insert(ButtonActionCondition::OutDownToOverDown);
}
if (flags & 0b100_0000) != 0 {
conditions.insert(ButtonActionCondition::OutDownToIdle);
}
if (flags & 0b1000_0000) != 0 {
conditions.insert(ButtonActionCondition::IdleToOverDown);
}
if (flags & 0b1_0000_0000) != 0 {
conditions.insert(ButtonActionCondition::OverDownToIdle);
}
let mut conditions = ButtonActionCondition::from_bits_truncate(flags);
let key_code = (flags >> 9) as u8;
if key_code != 0 {
conditions.insert(ButtonActionCondition::KeyPress);
}
conditions.set(ButtonActionCondition::KEY_PRESS, key_code != 0);
let action_data = if length >= 4 {
self.read_slice(length as usize - 4)?
} else if length == 0 {

View File

@ -201,9 +201,7 @@ pub fn tag_tests() -> Vec<TagTestData> {
records: vec![
ButtonRecord {
id: 1,
states: vec![ButtonState::Up, ButtonState::Over]
.into_iter()
.collect(),
states: ButtonState::UP | ButtonState::OVER,
depth: 1,
matrix: Matrix::identity(),
color_transform: ColorTransform::new(),
@ -212,9 +210,7 @@ pub fn tag_tests() -> Vec<TagTestData> {
},
ButtonRecord {
id: 2,
states: vec![ButtonState::Down, ButtonState::HitTest]
.into_iter()
.collect(),
states: ButtonState::DOWN | ButtonState::HIT_TEST,
depth: 1,
matrix: Matrix::identity(),
color_transform: ColorTransform::new(),
@ -223,9 +219,7 @@ pub fn tag_tests() -> Vec<TagTestData> {
},
],
actions: vec![ButtonAction {
conditions: vec![ButtonActionCondition::OverDownToOverUp]
.into_iter()
.collect(),
conditions: ButtonActionCondition::OVER_DOWN_TO_OVER_UP,
key_code: None,
action_data: &[0],
}],
@ -240,9 +234,7 @@ pub fn tag_tests() -> Vec<TagTestData> {
records: vec![
ButtonRecord {
id: 2,
states: vec![ButtonState::Up, ButtonState::Over]
.into_iter()
.collect(),
states: ButtonState::UP | ButtonState::OVER,
depth: 1,
matrix: Matrix::identity(),
color_transform: ColorTransform {
@ -264,9 +256,7 @@ pub fn tag_tests() -> Vec<TagTestData> {
},
ButtonRecord {
id: 3,
states: vec![ButtonState::Down, ButtonState::HitTest]
.into_iter()
.collect(),
states: ButtonState::DOWN | ButtonState::HIT_TEST,
depth: 1,
matrix: Matrix::identity(),
color_transform: ColorTransform {
@ -285,14 +275,12 @@ pub fn tag_tests() -> Vec<TagTestData> {
],
actions: vec![
ButtonAction {
conditions: vec![ButtonActionCondition::OverDownToOverUp]
.into_iter()
.collect(),
conditions: ButtonActionCondition::OVER_DOWN_TO_OVER_UP,
key_code: None,
action_data: &[150, 3, 0, 0, 65, 0, 38, 0], // trace("A");
},
ButtonAction {
conditions: vec![ButtonActionCondition::KeyPress].into_iter().collect(),
conditions: ButtonActionCondition::KEY_PRESS,
key_code: Some(3), // Home
action_data: &[150, 3, 0, 0, 66, 0, 38, 0], // trace("B");
},

View File

@ -5,7 +5,6 @@
//! https://www.adobe.com/content/dam/acom/en/devnet/pdf/swf-file-format-spec.pdf
use crate::string::SwfStr;
use bitflags::bitflags;
use std::collections::HashSet;
mod matrix;
@ -851,23 +850,24 @@ pub type ButtonSound = (CharacterId, SoundInfo);
#[derive(Debug, PartialEq, Clone)]
pub struct ButtonAction<'a> {
pub conditions: HashSet<ButtonActionCondition>,
pub conditions: ButtonActionCondition,
pub key_code: Option<u8>,
pub action_data: &'a [u8],
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum ButtonActionCondition {
IdleToOverDown,
OutDownToIdle,
OutDownToOverDown,
OverDownToOutDown,
OverDownToOverUp,
OverUpToOverDown,
OverUpToIdle,
IdleToOverUp,
OverDownToIdle,
KeyPress,
bitflags! {
pub struct ButtonActionCondition: u16 {
const IDLE_TO_OVER_UP = 1 << 0;
const OVER_UP_TO_IDLE = 1 << 1;
const OVER_UP_TO_OVER_DOWN = 1 << 2;
const OVER_DOWN_TO_OVER_UP = 1 << 3;
const OVER_DOWN_TO_OUT_DOWN = 1 << 4;
const OUT_DOWN_TO_OVER_DOWN = 1 << 5;
const OUT_DOWN_TO_IDLE = 1 << 6;
const IDLE_TO_OVER_DOWN = 1 << 7;
const OVER_DOWN_TO_IDLE = 1 << 8;
const KEY_PRESS = 1 << 9;
}
}
#[derive(Clone, Debug, PartialEq)]

View File

@ -1064,79 +1064,13 @@ impl<W: Write> Writer<W> {
} else {
writer.write_u16(0)?;
}
writer.write_u8(
if action
.conditions
.contains(&ButtonActionCondition::IdleToOverDown)
{
0b1000_0000
} else {
0
} | if action
.conditions
.contains(&ButtonActionCondition::OutDownToIdle)
{
0b100_0000
} else {
0
} | if action
.conditions
.contains(&ButtonActionCondition::OutDownToOverDown)
{
0b10_0000
} else {
0
} | if action
.conditions
.contains(&ButtonActionCondition::OverDownToOutDown)
{
0b1_0000
} else {
0
} | if action
.conditions
.contains(&ButtonActionCondition::OverDownToOverUp)
{
0b1000
} else {
0
} | if action
.conditions
.contains(&ButtonActionCondition::OverUpToOverDown)
{
0b100
} else {
0
} | if action
.conditions
.contains(&ButtonActionCondition::OverUpToIdle)
{
0b10
} else {
0
} | if action
.conditions
.contains(&ButtonActionCondition::IdleToOverUp)
{
0b1
} else {
0
},
)?;
let mut flags = if action
.conditions
.contains(&ButtonActionCondition::OverDownToIdle)
{
0b1
} else {
0
};
if action.conditions.contains(&ButtonActionCondition::KeyPress) {
let mut flags = action.conditions.bits();
if action.conditions.contains(ButtonActionCondition::KEY_PRESS) {
if let Some(key_code) = action.key_code {
flags |= key_code << 1;
flags |= (key_code as u16) << 9;
}
}
writer.write_u8(flags)?;
writer.write_u16(flags)?;
writer.output.write_all(&action.action_data)?;
}
}