2019-05-05 22:55:27 +00:00
|
|
|
use crate::backend::audio::SoundHandle;
|
2019-04-25 17:52:22 +00:00
|
|
|
use crate::character::Character;
|
2019-05-24 17:25:03 +00:00
|
|
|
use crate::display_object::DisplayObject;
|
2019-05-04 18:45:11 +00:00
|
|
|
use crate::font::Font;
|
2019-05-12 16:55:48 +00:00
|
|
|
use crate::prelude::*;
|
2019-05-24 17:25:03 +00:00
|
|
|
use gc_arena::{GcCell, MutationContext};
|
2019-04-25 17:52:22 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use swf::CharacterId;
|
|
|
|
|
2019-05-24 17:25:03 +00:00
|
|
|
pub struct Library<'gc> {
|
|
|
|
characters: HashMap<CharacterId, Character<'gc>>,
|
2019-05-03 00:17:02 +00:00
|
|
|
jpeg_tables: Option<Vec<u8>>,
|
2019-04-25 17:52:22 +00:00
|
|
|
}
|
|
|
|
|
2019-05-24 17:25:03 +00:00
|
|
|
impl<'gc> Library<'gc> {
|
|
|
|
pub fn new() -> Self {
|
2019-04-25 17:52:22 +00:00
|
|
|
Library {
|
|
|
|
characters: HashMap::new(),
|
2019-05-03 00:17:02 +00:00
|
|
|
jpeg_tables: None,
|
2019-04-25 17:52:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-24 17:25:03 +00:00
|
|
|
pub fn register_character(&mut self, id: CharacterId, character: Character<'gc>) {
|
2019-04-25 17:52:22 +00:00
|
|
|
// TODO(Herschel): What is the behavior if id already exists?
|
2019-07-19 08:32:41 +00:00
|
|
|
if !self.contains_character(id) {
|
|
|
|
self.characters.insert(id, character);
|
|
|
|
} else {
|
|
|
|
log::error!("Character ID collision: Tried to register ID {} twice", id);
|
|
|
|
}
|
2019-04-25 17:52:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn contains_character(&self, id: CharacterId) -> bool {
|
|
|
|
self.characters.contains_key(&id)
|
|
|
|
}
|
|
|
|
|
2019-05-24 17:25:03 +00:00
|
|
|
pub fn get_character(&self, id: CharacterId) -> Option<&Character<'gc>> {
|
2019-05-12 16:55:48 +00:00
|
|
|
self.characters.get(&id)
|
|
|
|
}
|
|
|
|
|
2019-05-24 17:25:03 +00:00
|
|
|
pub fn get_character_mut(&mut self, id: CharacterId) -> Option<&mut Character<'gc>> {
|
2019-05-12 16:55:48 +00:00
|
|
|
self.characters.get_mut(&id)
|
|
|
|
}
|
|
|
|
|
2019-04-25 17:52:22 +00:00
|
|
|
pub fn instantiate_display_object(
|
|
|
|
&self,
|
|
|
|
id: CharacterId,
|
2019-05-24 17:25:03 +00:00
|
|
|
gc_context: MutationContext<'gc, '_>,
|
2019-08-15 20:48:51 +00:00
|
|
|
) -> Result<DisplayNode<'gc>, Box<dyn std::error::Error>> {
|
|
|
|
let obj: Box<dyn DisplayObject<'gc>> = match self.characters.get(&id) {
|
2019-10-08 02:27:31 +00:00
|
|
|
Some(Character::EditText(edit_text)) => edit_text.clone(),
|
2019-05-07 10:22:58 +00:00
|
|
|
Some(Character::Graphic(graphic)) => graphic.clone(),
|
2019-05-12 16:55:48 +00:00
|
|
|
Some(Character::MorphShape(morph_shape)) => morph_shape.clone(),
|
2019-05-07 10:22:58 +00:00
|
|
|
Some(Character::MovieClip(movie_clip)) => movie_clip.clone(),
|
|
|
|
Some(Character::Button(button)) => button.clone(),
|
|
|
|
Some(Character::Text(text)) => text.clone(),
|
|
|
|
Some(_) => return Err("Not a DisplayObject".into()),
|
2019-08-23 04:54:00 +00:00
|
|
|
None => {
|
|
|
|
log::error!("Tried to instantiate non-registered character ID {}", id);
|
|
|
|
return Err("Character id doesn't exist".into());
|
|
|
|
}
|
2019-05-07 10:22:58 +00:00
|
|
|
};
|
2019-08-28 23:29:43 +00:00
|
|
|
let result = GcCell::allocate(gc_context, obj);
|
|
|
|
result
|
|
|
|
.write(gc_context)
|
2019-08-31 12:09:37 +00:00
|
|
|
.post_instantiation(gc_context, result);
|
2019-08-28 23:29:43 +00:00
|
|
|
Ok(result)
|
2019-04-25 17:52:22 +00:00
|
|
|
}
|
2019-05-03 00:17:02 +00:00
|
|
|
|
2019-05-04 18:45:11 +00:00
|
|
|
pub fn get_font(&self, id: CharacterId) -> Option<&Font> {
|
|
|
|
if let Some(&Character::Font(ref font)) = self.characters.get(&id) {
|
|
|
|
Some(font)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-05 22:55:27 +00:00
|
|
|
pub fn get_sound(&self, id: CharacterId) -> Option<SoundHandle> {
|
|
|
|
if let Some(Character::Sound(sound)) = self.characters.get(&id) {
|
|
|
|
Some(*sound)
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-03 00:17:02 +00:00
|
|
|
pub fn set_jpeg_tables(&mut self, data: Vec<u8>) {
|
2019-08-12 21:27:06 +00:00
|
|
|
let data = crate::backend::render::remove_invalid_jpeg_data(&data[..]).to_vec();
|
2019-05-03 00:17:02 +00:00
|
|
|
self.jpeg_tables = Some(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn jpeg_tables(&self) -> Option<&[u8]> {
|
|
|
|
self.jpeg_tables.as_ref().map(|data| &data[..])
|
|
|
|
}
|
2019-04-25 17:52:22 +00:00
|
|
|
}
|
2019-05-24 17:25:03 +00:00
|
|
|
|
|
|
|
impl Default for Library<'_> {
|
|
|
|
fn default() -> Self {
|
|
|
|
Library::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl<'gc> gc_arena::Collect for Library<'gc> {
|
|
|
|
#[inline]
|
|
|
|
fn trace(&self, cc: gc_arena::CollectionContext) {
|
|
|
|
for character in self.characters.values() {
|
|
|
|
character.trace(cc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|