use bevy::prelude::*;
use serde::{Deserialize, Serialize};
use crate::{
calc_func_id, graph::ExprError, Attribute, BoxedModifier, EvalContext, ExprHandle, Modifier,
ModifierContext, Module, ShaderWriter,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
pub struct SetVelocityCircleModifier {
pub center: ExprHandle,
pub axis: ExprHandle,
pub speed: ExprHandle,
}
impl SetVelocityCircleModifier {
fn eval(
&self,
module: &mut Module,
context: &mut dyn EvalContext,
) -> Result<String, ExprError> {
let func_id = calc_func_id(self);
let func_name = format!("set_velocity_circle_{0:016X}", func_id);
context.make_fn(
&func_name,
"transform: mat4x4<f32>, particle: ptr<function, Particle>",
module,
&mut |m: &mut Module, ctx: &mut dyn EvalContext| -> Result<String, ExprError> {
let center = ctx.eval(m, self.center)?;
let axis = ctx.eval(m, self.axis)?;
let speed = ctx.eval(m, self.speed)?;
Ok(format!(
r##" let delta = (*particle).{0} - ({1});
let radial = normalize(delta - dot(delta, {2}) * ({2}));
let radial_vec4 = transform * vec4<f32>(radial.xyz, 0.0);
(*particle).{3} = radial_vec4.xyz * ({4});
"##,
Attribute::POSITION.name(),
center,
axis,
Attribute::VELOCITY.name(),
speed,
))
},
)?;
let code = format!("{}(transform, &particle);\n", func_name);
Ok(code)
}
}
impl Modifier for SetVelocityCircleModifier {
fn context(&self) -> ModifierContext {
ModifierContext::Init | ModifierContext::Update
}
fn attributes(&self) -> &[Attribute] {
&[Attribute::POSITION, Attribute::VELOCITY]
}
fn boxed_clone(&self) -> BoxedModifier {
Box::new(*self)
}
fn apply(&self, module: &mut Module, context: &mut ShaderWriter) -> Result<(), ExprError> {
let code = self.eval(module, context)?;
context.main_code += &code;
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
pub struct SetVelocitySphereModifier {
pub center: ExprHandle,
pub speed: ExprHandle,
}
impl SetVelocitySphereModifier {
fn eval(
&self,
module: &mut Module,
context: &mut dyn EvalContext,
) -> Result<String, ExprError> {
let center = context.eval(module, self.center)?;
let speed = context.eval(module, self.speed)?;
let code = format!(
"particle.{} = normalize(particle.{} - ({})) * ({});\n",
Attribute::VELOCITY.name(),
Attribute::POSITION.name(),
center,
speed
);
Ok(code)
}
}
impl Modifier for SetVelocitySphereModifier {
fn context(&self) -> ModifierContext {
ModifierContext::Init | ModifierContext::Update
}
fn attributes(&self) -> &[Attribute] {
&[Attribute::POSITION, Attribute::VELOCITY]
}
fn boxed_clone(&self) -> BoxedModifier {
Box::new(*self)
}
fn apply(&self, module: &mut Module, context: &mut ShaderWriter) -> Result<(), ExprError> {
let code = self.eval(module, context)?;
context.main_code += &code;
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
pub struct SetVelocityTangentModifier {
pub origin: ExprHandle,
pub axis: ExprHandle,
pub speed: ExprHandle,
}
impl SetVelocityTangentModifier {
fn eval(
&self,
module: &mut Module,
context: &mut dyn EvalContext,
) -> Result<String, ExprError> {
let func_id = calc_func_id(self);
let func_name = format!("set_velocity_tangent_{0:016X}", func_id);
context.make_fn(
&func_name,
"transform: mat4x4<f32>, particle: ptr<function, Particle>",
module,
&mut |m: &mut Module, ctx: &mut dyn EvalContext| -> Result<String, ExprError> {
let origin = ctx.eval(m, self.origin)?;
let axis = ctx.eval(m, self.axis)?;
let speed = ctx.eval(m, self.speed)?;
Ok(format!(
r##" let radial = (*particle).{0} - ({1});
let tangent = normalize(cross({2}, radial));
let tangent_vec4 = transform * vec4<f32>(tangent.xyz, 0.0);
(*particle).{3} = tangent_vec4.xyz * ({4});
"##,
Attribute::POSITION.name(),
origin,
axis,
Attribute::VELOCITY.name(),
speed,
))
},
)?;
let code = format!("{}(transform, &particle);\n", func_name);
Ok(code)
}
}
impl Modifier for SetVelocityTangentModifier {
fn context(&self) -> ModifierContext {
ModifierContext::Init | ModifierContext::Update
}
fn attributes(&self) -> &[Attribute] {
&[Attribute::POSITION, Attribute::VELOCITY]
}
fn boxed_clone(&self) -> BoxedModifier {
Box::new(*self)
}
fn apply(&self, module: &mut Module, context: &mut ShaderWriter) -> Result<(), ExprError> {
let code = self.eval(module, context)?;
context.main_code += &code;
Ok(())
}
}