use serde::{Deserialize, Serialize};
use crate::ecs::audio::components::AudioBus;
use crate::render::wgpu::texture_cache::{SamplerSettings, TextureUsage};
use super::asset_uuid::AssetUuid;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SceneAudioSource {
#[serde(default)]
pub audio_uuid: Option<AssetUuid>,
#[serde(default)]
pub audio_name: Option<String>,
#[serde(default = "default_volume")]
pub volume: f32,
#[serde(default)]
pub looping: bool,
#[serde(default)]
pub playing: bool,
#[serde(default)]
pub spatial: bool,
#[serde(default)]
pub reverb: bool,
#[serde(default)]
pub bus: AudioBus,
#[serde(default = "default_min_distance")]
pub min_distance: f32,
#[serde(default = "default_max_distance")]
pub max_distance: f32,
#[serde(default)]
pub reverb_zones: Vec<(String, f32)>,
#[serde(default)]
pub random_clips: Vec<String>,
#[serde(default)]
pub random_pick: bool,
}
fn default_volume() -> f32 {
1.0
}
fn default_min_distance() -> f32 {
1.0
}
fn default_max_distance() -> f32 {
50.0
}
impl SceneAudioSource {
pub fn from_name(name: impl Into<String>) -> Self {
Self {
audio_uuid: None,
audio_name: Some(name.into()),
volume: 1.0,
looping: false,
playing: false,
spatial: false,
reverb: false,
bus: AudioBus::Sfx,
min_distance: 1.0,
max_distance: 50.0,
reverb_zones: Vec::new(),
random_clips: Vec::new(),
random_pick: false,
}
}
pub fn from_uuid(uuid: AssetUuid) -> Self {
Self {
audio_uuid: Some(uuid),
audio_name: None,
volume: 1.0,
looping: false,
playing: false,
spatial: false,
reverb: false,
bus: AudioBus::Sfx,
min_distance: 1.0,
max_distance: 50.0,
reverb_zones: Vec::new(),
random_clips: Vec::new(),
random_pick: false,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ScenePrefabInstance {
#[serde(default)]
pub prefab_uuid: Option<AssetUuid>,
#[serde(default)]
pub prefab_path: Option<String>,
#[serde(default)]
pub prefab_name: Option<String>,
}
impl ScenePrefabInstance {
pub fn from_uuid(uuid: AssetUuid) -> Self {
Self {
prefab_uuid: Some(uuid),
prefab_path: None,
prefab_name: None,
}
}
pub fn from_path(path: impl Into<String>) -> Self {
Self {
prefab_uuid: None,
prefab_path: Some(path.into()),
prefab_name: None,
}
}
pub fn from_name(name: impl Into<String>) -> Self {
Self {
prefab_uuid: None,
prefab_path: None,
prefab_name: Some(name.into()),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmbeddedTexture {
pub name: String,
pub data: EmbeddedTextureData,
#[serde(default = "default_embedded_usage")]
pub usage: TextureUsage,
#[serde(default)]
pub sampler: SamplerSettings,
}
fn default_embedded_usage() -> TextureUsage {
TextureUsage::Color
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EmbeddedTextureData {
Rgba {
#[serde(with = "base64_bytes")]
rgba_data: Vec<u8>,
width: u32,
height: u32,
},
Png {
#[serde(with = "base64_bytes")]
png_data: Vec<u8>,
},
}
mod base64_bytes {
use base64::{Engine, engine::general_purpose::STANDARD};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub fn serialize<S: Serializer>(data: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
STANDARD.encode(data).serialize(serializer)
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
let string = String::deserialize(deserializer)?;
STANDARD.decode(&string).map_err(serde::de::Error::custom)
}
}
impl EmbeddedTexture {
pub fn from_rgba(name: impl Into<String>, rgba_data: Vec<u8>, width: u32, height: u32) -> Self {
Self {
name: name.into(),
data: EmbeddedTextureData::Rgba {
rgba_data,
width,
height,
},
usage: TextureUsage::Color,
sampler: SamplerSettings::DEFAULT,
}
}
pub fn from_png(name: impl Into<String>, png_data: Vec<u8>) -> Self {
Self {
name: name.into(),
data: EmbeddedTextureData::Png { png_data },
usage: TextureUsage::Color,
sampler: SamplerSettings::DEFAULT,
}
}
pub fn with_usage(mut self, usage: TextureUsage) -> Self {
self.usage = usage;
self
}
pub fn with_sampler(mut self, sampler: SamplerSettings) -> Self {
self.sampler = sampler;
self
}
pub fn to_rgba(&self) -> Option<(Vec<u8>, u32, u32)> {
self.data.to_rgba()
}
}
impl EmbeddedTextureData {
pub fn to_rgba(&self) -> Option<(Vec<u8>, u32, u32)> {
match self {
Self::Rgba {
rgba_data,
width,
height,
} => Some((rgba_data.clone(), *width, *height)),
Self::Png { png_data } => {
if let Ok(img) = image::load_from_memory(png_data) {
let rgba = img.to_rgba8();
let (width, height) = rgba.dimensions();
Some((rgba.into_raw(), width, height))
} else {
None
}
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EmbeddedAudio {
#[serde(with = "base64_bytes")]
pub data: Vec<u8>,
}
impl EmbeddedAudio {
pub fn from_bytes(data: Vec<u8>) -> Self {
Self { data }
}
pub fn data(&self) -> &[u8] {
&self.data
}
}