1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
use std::rc::Rc;
use crate::engine::d2::asset::{AssetPack, File};
use super::{BlendMode, EmitterSprite, Texture};
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum EmitterType {
Gravity,
Radial,
}
impl Default for EmitterType {
fn default() -> Self {
Self::Gravity
}
}
/// A particle system configuration, that can be used to create emitter sprites. The configuration is
/// loaded from a .pex file, authored in a tool such as Particle Designer.
/// *
/// NOTE: There are some restrictions to keep in mind when using Particle Designer:
/// *
/// - Particle coloring is not supported.
/// - Only normal and additive blend modes are supported.
/// *
/// *
/// Also keep in mind that gratuitous particle systems are a great way to kill performance,
/// especially on mobile. Try to keep maxParticles as low as possible to achieve the desired effect.
#[derive(Default, Debug)]
pub struct EmitterMold {
pub texture: Option<Rc<dyn Texture>>,
pub max_particles: usize,
pub type_: EmitterType,
// pub emitX: f32,
pub emit_x_variance: f32,
// pub emitY: f32,
pub emit_y_variance: f32,
pub alpha_start: f32,
pub alpha_start_variance: f32,
pub alpha_end: f32,
pub alpha_end_variance: f32,
pub angle: f32,
pub angle_variance: f32,
pub duration: f32,
pub gravity_x: f32,
pub gravity_y: f32,
pub max_radius: f32,
pub max_radius_variance: f32,
pub min_radius: f32,
pub lifespan_variance: f32,
pub lifespan: f32,
pub rotate_per_second: f32,
pub rotate_per_second_variance: f32,
pub rotation_start: f32,
pub rotation_start_variance: f32,
pub rotation_end: f32,
pub rotation_end_variance: f32,
pub size_start: f32,
pub size_start_variance: f32,
pub size_end: f32,
pub size_end_variance: f32,
pub speed: f32,
pub speed_variance: f32,
pub radial_accel: f32,
pub radial_accel_variance: f32,
pub tangential_accel: f32,
pub tangential_accel_variance: f32,
pub blend_mode: Option<BlendMode>,
file: Option<Box<dyn File>>,
}
impl EmitterMold {
/// Creates an EmitterMold using files in an asset pack.
/// @param name The path to the particle system within the asset pack, excluding the .pex suffix.
pub fn new(pack: impl AssetPack, name: String) -> Self {
let instance = Self::default();
// let _file = pack.get_file(name + ".pex");
// let xml = Xml::parse(_file.toString());
// let blend_funcSource = 0;
// let blend_funcDestination = 0;
// // The basename of the pex file's path, where we'll find the textures
// let idx = name.rfind("/");
// let basePath = if idx >= 0 { name[..idx + 1] } else { "" };
// for element in xml.firstElement().elements() {
// match element.nodeName.to_lowercase() {
// "texture" => instance.texture = pack.get_texture(basePath + element.get("name").remove_file_extension()),
// "angle" => instance.angle = Self::getValue(element),
// "anglevariance" => instance.angleVariance = Self::getValue(element),
// "blendfuncdestination" => blend_funcDestination = Self::getValue(element) as usize,
// "blendfuncsource" => blend_funcSource = Self::getValue(element) as usize,
// "duration" => instance.duration = Self::getValue(element),
// "emittertype" => {
// instance.type_ = if Self::getValue(element) as usize == 0 { EmitterType::Gravity } else { EmitterType::Radial };
// }
// "finishcolor" => instance.alphaEnd = Self::getFloat(element, "alpha"),
// "finishcolorvariance" => instance.alphaEndVariance = Self::getFloat(element, "alpha"),
// "finishparticlesize" => instance.sizeEnd = Self::getValue(element),
// "finishparticlesizevariance" => instance.sizeEndVariance = Self::getValue(element),
// "gravity" => {
// instance.gravityX = Self::getX(element);
// instance.gravityY = Self::getY(element);
// }
// "maxparticles" => instance.maxParticles = Self::getValue(element) as usize,
// "maxradius" => instance.maxRadius = Self::getValue(element),
// "maxradiusvariance" => instance.maxRadiusVariance = Self::getValue(element),
// "minradius" => instance.minRadius = Self::getValue(element),
// "particlelifespan" => instance.lifespan = Self::getValue(element),
// "particlelifespanvariance" => instance.lifespanVariance = Self::getValue(element),
// "radialaccelvariance" => instance.radialAccelVariance = Self::getValue(element),
// "radialacceleration" => instance.radialAccel = Self::getValue(element),
// "rotatepersecond" => instance.rotatePerSecond = Self::getValue(element),
// "rotatepersecondvariance" => instance.rotatePerSecondVariance = Self::getValue(element),
// "rotationend" => instance.rotationEnd = Self::getValue(element),
// "rotationendvariance" => instance.rotationEndVariance = Self::getValue(element),
// "rotationstart" => instance.rotation_start = Self::getValue(element),
// "rotationstartvariance" => instance.rotation_startVariance = Self::getValue(element),
// // "sourceposition" =>
// "sourcepositionvariance" => {
// instance.emitXVariance = Self::getX(element);
// instance.emitYVariance = Self::getY(element);
// }
// "speed" => instance.speed = Self::getValue(element),
// "speedvariance" => instance.speedVariance = Self::getValue(element),
// "startcolor" => instance.alphaStart = Self::getFloat(element, "alpha"),
// "startcolorvariance" => instance.alphaStartVariance = Self::getFloat(element, "alpha"),
// "startparticlesize" => instance.sizeStart = Self::getValue(element),
// "startparticlesizevariance" => instance.sizeStartVariance = Self::getValue(element),
// "tangentialaccelvariance" => instance.tangentialAccelVariance = Self::getValue(element),
// "tangentialacceleration" => instance.tangentialAccel = Self::getValue(element),
// }
// }
// // Handle weird Particle Designer output for emitters with a duration
// if instance.lifespan <= 0 {
// instance.lifespan = instance.duration;
// }
// if blend_funcSource == 1 && blend_funcDestination == 1 {
// instance.blendMode = BlendMode::Add;
// } else if blend_funcSource == 1 && blend_funcDestination == 771 {
// instance.blendMode = None; // Normal
// } else if blend_funcSource != 0 || blend_funcDestination != 0 {
// // log::warn!(
// // "Unsupported particle blend functions [emitter: {}, source: {}, dest {}"), name, blend_funcSource, blend_funcDestination)
// // );
// }
// instance
unimplemented!()
}
/// Disposes the source .pex File used to create this EmitterMold. This can free up some memory,
/// if you don't intend to recreate this EmitterMold later from the same AssetPack.
/// *
/// @returns This instance, for chaining.
pub fn dispose_files(&mut self) -> &Self {
if let Some(ref mut file) = self.file {
file.dispose();
}
self
}
/// Creates a new EmitterSprite using this mold.
pub fn create_emitter(&self) -> EmitterSprite {
EmitterSprite::new(self)
}
// // static
// fn getFloat(xml: Xml, name: String) -> f32 {
// xml.get(name).parse::<f32>()
// }
// // static
// #[inline]
// fn getValue(xml: Xml) -> f32 {
// Self::getFloat(xml, "value")
// }
// // static
// #[inline]
// fn getX(xml: Xml) -> f32 {
// Self::getFloat(xml, "x")
// }
// // static
// #[inline]
// fn getY(xml: Xml) -> f32 {
// Self::getFloat(xml, "y")
// }
}