• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

djeedai / bevy_hanabi / 10662010223

02 Sep 2024 06:32AM UTC coverage: 59.087% (-0.02%) from 59.11%
10662010223

push

github

web-flow
Support sampling normal distribution in expressions (#362)

2 of 6 new or added lines in 1 file covered. (33.33%)

1 existing line in 1 file now uncovered.

3495 of 5915 relevant lines covered (59.09%)

23.04 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

54.42
/src/graph/expr.rs
1
//! Expression API
2
//!
3
//! This module contains the low-level _Expression API_, designed to produce
4
//! highly customizable modifier behaviors through a code-first API focused on
5
//! runtime and serialization. For asset editing, the higher-level [Node API]
6
//! offers an easier-to-use abstraction built on top of the Expression API.
7
//!
8
//! # Modules and expressions
9
//!
10
//! A particle effect is composed of a series [`Modifier`]s decribing how to
11
//! initialize and update (simulate) the particles of the effect. Choosing which
12
//! modifier to add to an effect provides the user some limited level of
13
//! customizing. However modifiers alone cannot provide enough customizing to
14
//! build visual effects. For this reason, modifier inputs can be further
15
//! customized with _expressions_. An expression produces a value which is
16
//! assigned to the input. That value can be constant, in which case it will be
17
//! hard-coded into the generated WGSL shader, for performance reasons.
18
//! Alternatively, that value can vary based on other quantities, like an effect
19
//! property, a particle attribute, or some built-in simulation variable like
20
//! the simulation time.
21
//!
22
//! An expression is represented by the [`Expr`] enum. Expressions can be
23
//! combined together to form more complex expression; for example, the Add
24
//! expression computes the sum between two other expressions. [`Expr`]
25
//! represents a form of abstraction over the actual WGSL shader code, and is
26
//! generally closely related to the actual expressions of the WGSL language
27
//! itself.
28
//!
29
//! An expression often refers to other expressions. However, [`Expr`] as an
30
//! enum cannot directly contain other [`Expr`], otherwise the type would become
31
//! infinitely recursive. Instead, each expression is stored into a [`Module`]
32
//! and indexed by an [`ExprHandle`], a non-zero index referencing the
33
//! expression inside the module. This indirection avoids the recursion issue.
34
//! This means all expressions are implicitly associated with a unique module,
35
//! and care must be taken to not mix exressions from different modules.
36
//!
37
//! Each [`EffectAsset`] contains a single [`Module`] storing all the [`Expr`]
38
//! used in all its modifiers.
39
//!
40
//! # Kinds of expressions
41
//!
42
//! Expressions can be grouped into various kinds, for the sake of
43
//! comprehension:
44
//! - Literal expressions represent a constant, which will be hard-coded into
45
//!   the final WGSL shader code. Expressions like `1.42` or `vec3<f32>(0.)` are
46
//!   literal expressions in WGSL, and are represented by a [`LiteralExpr`].
47
//! - Built-in expressions represent specific built-in values provided by the
48
//!   simulation context. For example, the current simulation time is a built-in
49
//!   expression accessible from the shader code of any visual effect to animate
50
//!   it. A built-in expression is represented by a [`BuiltInExpr`].
51
//! - Attribute expressions represent the value of an attribute of a particle. A
52
//!   typical example is the particle position, represented by
53
//!   [`Attribute::POSITION`], which can be obtained as an expression through an
54
//!   [`AttributeExpr`].
55
//! - Property expressions represent the value of a visual effect property, a
56
//!   quantity assigned by the user on the CPU side and uploaded each frame into
57
//!   the GPU for precise per-frame control over an effect. It's represented by
58
//!   a [`PropertyExpr`].
59
//! - Unary and binary operations are expressions taking one or two operand
60
//!   expressions and transforming them. A typical example is the Add operator,
61
//!   which takes two operand expressions and produces their sum.
62
//!
63
//! # Building expressions
64
//!
65
//! The fundamental way to build expressions is to directly write them into a
66
//! [`Module`] itself. The [`Module`] type contains various methods to create
67
//! new expressions and immediately write them.
68
//!
69
//! ```
70
//! # use bevy_hanabi::*;
71
//! let mut module = Module::default();
72
//!
73
//! // Build and write a literal expression into the module.
74
//! let expr = module.lit(3.42);
75
//! ```
76
//!
77
//! Due to the code-first nature of the Expression API however, that approach
78
//! can be very verbose. Instead, users are encouraged to use an [`ExprWriter`],
79
//! a simple utility to build expressions with a shortened syntax. Once an
80
//! expression is built, it can be written into the underlying [`Module`]. This
81
//! approach generally makes the code more readable, and is therefore highly
82
//! encouraged, but is not mandatory.
83
//!
84
//! ```
85
//! # use bevy_hanabi::*;
86
//! // Create a writer owning a new Module
87
//! let mut w = ExprWriter::new();
88
//!
89
//! // Build a complex expression: max(3.42, properties.my_prop)
90
//! let prop = w.add_property("my_property", 3.0.into());
91
//! let expr = w.lit(3.42).max(w.prop(prop));
92
//!
93
//! // Finalize the expression and write it into the Module. The returned handle can
94
//! // be assign to a modifier input.
95
//! let handle = expr.expr();
96
//!
97
//! // Finish using the writer and recover the Module with all written expressions
98
//! let module = w.finish();
99
//! ```
100
//!
101
//! [Node API]: crate::graph::node
102
//! [`Modifier`]: crate::Modifier
103
//! [`EffectAsset`]: crate::EffectAsset
104

105
use std::{cell::RefCell, num::NonZeroU32, rc::Rc};
106

107
use bevy::{prelude::default, reflect::Reflect};
108
use serde::{Deserialize, Serialize};
109
use thiserror::Error;
110

111
use super::Value;
112
use crate::{
113
    Attribute, ModifierContext, ParticleLayout, Property, PropertyLayout, ScalarType,
114
    TextureLayout, TextureSlot, ToWgslString, ValueType, VectorType,
115
};
116

117
/// A one-based ID into a collection of a [`Module`].
118
type Id = NonZeroU32;
119

120
/// Handle of an expression inside a given [`Module`].
121
///
122
/// A handle uniquely references an [`Expr`] stored inside a [`Module`]. It's a
123
/// lightweight representation, similar to a simple array index. For this
124
/// reason, it's easily copyable. However it's also lacking any kind of error
125
/// checking, and mixing handles to different modules produces undefined
126
/// behaviors (like an index does when indexing the wrong array).
127
#[derive(
128
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
129
)]
130
#[repr(transparent)]
131
#[serde(transparent)]
132
pub struct ExprHandle {
133
    id: Id,
134
}
135

136
impl ExprHandle {
137
    /// Create a new handle from a 1-based [`Id`].
138
    #[allow(dead_code)]
139
    fn new(id: Id) -> Self {
×
140
        Self { id }
141
    }
142

143
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
144
    /// the index is known to be non-zero already.
145
    #[allow(unsafe_code)]
146
    unsafe fn new_unchecked(id: usize) -> Self {
226✔
147
        debug_assert!(id != 0);
452✔
148
        Self {
149
            id: NonZeroU32::new_unchecked(id as u32),
226✔
150
        }
151
    }
152

153
    /// Get the zero-based index into the array of the module.
154
    fn index(&self) -> usize {
383✔
155
        (self.id.get() - 1) as usize
383✔
156
    }
157
}
158

159
/// Handle of a property inside a given [`Module`].
160
///
161
/// A handle uniquely references a [`Property`] stored inside a [`Module`]. It's
162
/// a lightweight representation, similar to a simple array index. For this
163
/// reason, it's easily copyable. However it's also lacking any kind of error
164
/// checking, and mixing handles to different modules produces undefined
165
/// behaviors (like an index does when indexing the wrong array).
166
#[derive(
167
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
168
)]
169
#[repr(transparent)]
170
#[serde(transparent)]
171
pub struct PropertyHandle {
172
    id: Id,
173
}
174

175
impl PropertyHandle {
176
    /// Create a new handle from a 1-based [`Id`].
177
    #[allow(dead_code)]
178
    fn new(id: Id) -> Self {
×
179
        Self { id }
180
    }
181

182
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
183
    /// the index is known to be non-zero already.
184
    #[allow(unsafe_code)]
185
    unsafe fn new_unchecked(id: usize) -> Self {
6✔
186
        debug_assert!(id != 0);
12✔
187
        Self {
188
            id: NonZeroU32::new_unchecked(id as u32),
6✔
189
        }
190
    }
191

192
    /// Get the zero-based index into the array of the module.
193
    fn index(&self) -> usize {
2✔
194
        (self.id.get() - 1) as usize
2✔
195
    }
196
}
197

198
/// Handle of a texture inside a given [`Module`].
199
///
200
/// A handle uniquely references a [`TextureSlot`] stored inside a [`Module`].
201
/// It's a lightweight representation, similar to a simple array index. For this
202
/// reason, it's easily copyable. However it's also lacking any kind of error
203
/// checking, and mixing handles to different modules produces undefined
204
/// behaviors (like an index does when indexing the wrong array).
205
#[derive(
206
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Reflect, Serialize, Deserialize,
207
)]
208
#[repr(transparent)]
209
#[serde(transparent)]
210
pub struct TextureHandle {
211
    id: Id,
212
}
213

214
impl TextureHandle {
215
    /// Create a new handle from a 1-based [`Id`].
216
    #[allow(dead_code)]
217
    fn new(id: Id) -> Self {
×
218
        Self { id }
219
    }
220

221
    /// Create a new handle from a 1-based [`Id`] as a `usize`, for cases where
222
    /// the index is known to be non-zero already.
223
    #[allow(unsafe_code)]
224
    unsafe fn new_unchecked(id: usize) -> Self {
×
225
        debug_assert!(id != 0);
×
226
        Self {
227
            id: NonZeroU32::new_unchecked(id as u32),
×
228
        }
229
    }
230

231
    /// Get the zero-based index into the array of the module.
232
    #[allow(dead_code)]
233
    fn index(&self) -> usize {
×
234
        (self.id.get() - 1) as usize
×
235
    }
236
}
237

238
/// Container for expressions.
239
///
240
/// A module represents a storage for a set of expressions used in a single
241
/// [`EffectAsset`]. Modules are not reusable accross effect assets; each effect
242
/// asset owns a single module, containing all the expressions used in all the
243
/// modifiers attached to that asset. However, for convenience, a module can be
244
/// cloned into an unrelated module, and the clone can be assigned to another
245
/// effect asset.
246
///
247
/// Modules are built incrementally. Expressions are written into the module
248
/// through convenience helpers like [`lit()`] or [`attr()`]. Alternatively, an
249
/// [`ExprWriter`] can be used to populate a new or existing module. Either way,
250
/// once an expression is written into a module, it cannot be modified or
251
/// deleted. Modules are not designed to be used as editing structures, but as
252
/// storage and serialization ones.
253
///
254
/// [`EffectAsset`]: crate::EffectAsset
255
/// [`lit()`]: Module::lit
256
/// [`attr()`]: Module::attr
257
#[derive(Debug, Default, Clone, PartialEq, Hash, Reflect, Serialize, Deserialize)]
258
pub struct Module {
259
    /// Expressions defined in the module.
260
    expressions: Vec<Expr>,
261
    /// Properties used as part of a [`PropertyExpr`].
262
    properties: Vec<Property>,
263
    /// Texture layout.
264
    texture_layout: TextureLayout,
265
}
266

267
macro_rules! impl_module_unary {
268
    ($t: ident, $T: ident) => {
269
        #[doc = concat!("Build a [`UnaryOperator::", stringify!($T), "`](crate::graph::expr::UnaryOperator::", stringify!($T),") unary expression and append it to the module.\n\nThis is a shortcut for [`unary(UnaryOperator::", stringify!($T), ", inner)`](crate::graph::expr::Module::unary).")]
270
        #[inline]
271
        pub fn $t(&mut self, inner: ExprHandle) -> ExprHandle {
34✔
272
            self.unary(UnaryOperator::$T, inner)
34✔
273
        }
274
    };
275
}
276

277
macro_rules! impl_module_binary {
278
    ($t: ident, $T: ident) => {
279
        #[doc = concat!("Build a [`BinaryOperator::", stringify!($T), "`](crate::graph::expr::BinaryOperator::", stringify!($T),") binary expression and append it to the module.\n\nThis is a shortcut for [`binary(BinaryOperator::", stringify!($T), ", left, right)`](crate::graph::expr::Module::binary).")]
280
        #[inline]
281
        pub fn $t(&mut self, left: ExprHandle, right: ExprHandle) -> ExprHandle {
33✔
282
            self.binary(BinaryOperator::$T, left, right)
33✔
283
        }
284
    };
285
}
286

287
macro_rules! impl_module_ternary {
288
    ($t: ident, $T: ident) => {
289
        #[doc = concat!("Build a [`TernaryOperator::", stringify!($T), "`](crate::graph::expr::TernaryOperator::", stringify!($T),") ternary expression and append it to the module.\n\nThis is a shortcut for [`ternary(TernaryOperator::", stringify!($T), ", first, second, third)`](crate::graph::expr::Module::ternary).")]
290
        #[inline]
291
        pub fn $t(&mut self, first: ExprHandle, second: ExprHandle, third: ExprHandle) -> ExprHandle {
3✔
292
            self.ternary(TernaryOperator::$T, first, second, third)
3✔
293
        }
294
    };
295
}
296

297
impl Module {
298
    /// Create a new module from an existing collection of expressions.
299
    pub fn from_raw(expr: Vec<Expr>) -> Self {
×
300
        Self {
301
            expressions: expr,
302
            properties: vec![],
×
303
            texture_layout: default(),
×
304
        }
305
    }
306

307
    /// Add a new property to the module.
308
    ///
309
    /// See [`Property`] for more details on what effect properties are.
310
    ///
311
    /// # Panics
312
    ///
313
    /// Panics if a property with the same name already exists.
314
    pub fn add_property(
6✔
315
        &mut self,
316
        name: impl Into<String>,
317
        default_value: Value,
318
    ) -> PropertyHandle {
319
        let name = name.into();
6✔
320
        assert!(!self.properties.iter().any(|p| p.name() == name));
13✔
321
        self.properties.push(Property::new(name, default_value));
6✔
322
        // SAFETY - We just pushed a new property into the array, so its length is
323
        // non-zero.
324
        #[allow(unsafe_code)]
6✔
325
        unsafe {
326
            PropertyHandle::new_unchecked(self.properties.len())
6✔
327
        }
328
    }
329

330
    /// Get an existing property by handle.
331
    ///
332
    /// Existing properties are properties previously created with
333
    /// [`add_property()`].
334
    ///
335
    /// [`add_property()`]: crate::Module::add_property
336
    pub fn get_property(&self, property: PropertyHandle) -> Option<&Property> {
2✔
337
        self.properties.get(property.index())
2✔
338
    }
339

340
    /// Get an existing property by name.
341
    ///
342
    /// Existing properties are properties previously created with
343
    /// [`add_property()`].
344
    ///
345
    /// [`add_property()`]: crate::Module::add_property
346
    pub fn get_property_by_name(&self, name: &str) -> Option<PropertyHandle> {
×
347
        self.properties
×
348
            .iter()
349
            .enumerate()
350
            .find(|(_, prop)| prop.name() == name)
×
351
            .map(|(index, _)| PropertyHandle::new(NonZeroU32::new(index as u32 + 1).unwrap()))
×
352
    }
353

354
    /// Get the list of existing properties.
355
    pub fn properties(&self) -> &[Property] {
9✔
356
        &self.properties
9✔
357
    }
358

359
    /// Add a new texture to the module.
360
    ///
361
    /// See [`TextureSlot`] for more details on what effect textures are.
362
    ///
363
    /// # Panics
364
    ///
365
    /// Panics if a texture with the same name already exists.
366
    pub fn add_texture(&mut self, name: impl Into<String>) -> TextureHandle {
×
367
        let name = name.into();
×
368
        assert!(!self.texture_layout.layout.iter().any(|t| t.name == name));
×
369
        self.texture_layout.layout.push(TextureSlot { name });
×
370
        // SAFETY - We just pushed a new property into the array, so its length is
371
        // non-zero.
372
        #[allow(unsafe_code)]
×
373
        unsafe {
374
            TextureHandle::new_unchecked(self.texture_layout.layout.len())
×
375
        }
376
    }
377

378
    /// Append a new expression to the module.
379
    fn push(&mut self, expr: impl Into<Expr>) -> ExprHandle {
225✔
380
        self.expressions.push(expr.into());
225✔
381
        #[allow(unsafe_code)]
225✔
382
        unsafe {
383
            ExprHandle::new_unchecked(self.expressions.len())
225✔
384
        }
385
    }
386

387
    /// Build a literal expression and append it to the module.
388
    #[inline]
389
    pub fn lit<V>(&mut self, value: V) -> ExprHandle
73✔
390
    where
391
        Value: From<V>,
392
    {
393
        self.push(Expr::Literal(LiteralExpr::new(value)))
73✔
394
    }
395

396
    /// Build an attribute expression and append it to the module.
397
    #[inline]
398
    pub fn attr(&mut self, attr: Attribute) -> ExprHandle {
26✔
399
        self.push(Expr::Attribute(AttributeExpr::new(attr)))
26✔
400
    }
401

402
    /// Build a property expression and append it to the module.
403
    ///
404
    /// A property expression retrieves the value of the given property.
405
    #[inline]
406
    pub fn prop(&mut self, property: PropertyHandle) -> ExprHandle {
3✔
407
        self.push(Expr::Property(PropertyExpr::new(property)))
3✔
408
    }
409

410
    /// Build a built-in expression and append it to the module.
411
    #[inline]
412
    pub fn builtin(&mut self, op: BuiltInOperator) -> ExprHandle {
30✔
413
        self.push(Expr::BuiltIn(BuiltInExpr::new(op)))
30✔
414
    }
415

416
    /// Build a unary expression and append it to the module.
417
    ///
418
    /// The handle to the expression representing the operand of the unary
419
    /// operation must be valid, that is reference an expression
420
    /// contained in the current [`Module`].
421
    ///
422
    /// # Panics
423
    ///
424
    /// Panics in some cases if the operand handle do not reference an existing
425
    /// expression in the current module. Note however that this check can
426
    /// miss some invalid handles (false negative), so only represents an
427
    /// extra safety net that users shouldn't rely exclusively on
428
    /// to ensure the operand handles are valid. Instead, it's the
429
    /// responsibility of the user to ensure the operand handle references an
430
    /// existing expression in the current [`Module`].
431
    #[inline]
432
    pub fn unary(&mut self, op: UnaryOperator, inner: ExprHandle) -> ExprHandle {
34✔
433
        assert!(inner.index() < self.expressions.len());
34✔
434
        self.push(Expr::Unary { op, expr: inner })
34✔
435
    }
436

437
    impl_module_unary!(abs, Abs);
438
    impl_module_unary!(all, All);
439
    impl_module_unary!(any, Any);
440
    impl_module_unary!(ceil, Ceil);
441
    impl_module_unary!(cos, Cos);
442
    impl_module_unary!(exp, Exp);
443
    impl_module_unary!(exp2, Exp2);
444
    impl_module_unary!(floor, Floor);
445
    impl_module_unary!(fract, Fract);
446
    impl_module_unary!(inverse_sqrt, InvSqrt);
447
    impl_module_unary!(length, Length);
448
    impl_module_unary!(log, Log);
449
    impl_module_unary!(log2, Log2);
450
    impl_module_unary!(normalize, Normalize);
451
    impl_module_unary!(pack4x8snorm, Pack4x8snorm);
452
    impl_module_unary!(pack4x8unorm, Pack4x8unorm);
453
    impl_module_unary!(saturate, Saturate);
454
    impl_module_unary!(sign, Sign);
455
    impl_module_unary!(sin, Sin);
456
    impl_module_unary!(sqrt, Sqrt);
457
    impl_module_unary!(tan, Tan);
458
    impl_module_unary!(unpack4x8snorm, Unpack4x8snorm);
459
    impl_module_unary!(unpack4x8unorm, Unpack4x8unorm);
460
    impl_module_unary!(w, W);
461
    impl_module_unary!(x, X);
462
    impl_module_unary!(y, Y);
463
    impl_module_unary!(z, Z);
464

465
    /// Build a binary expression and append it to the module.
466
    ///
467
    /// The handles to the expressions representing the left and right operands
468
    /// of the binary operation must be valid, that is reference expressions
469
    /// contained in the current [`Module`].
470
    ///
471
    /// # Panics
472
    ///
473
    /// Panics in some cases if either of the left or right operand handles do
474
    /// not reference existing expressions in the current module. Note however
475
    /// that this check can miss some invalid handles (false negative), so only
476
    /// represents an extra safety net that users shouldn't rely exclusively on
477
    /// to ensure the operand handles are valid. Instead, it's the
478
    /// responsibility of the user to ensure handles reference existing
479
    /// expressions in the current [`Module`].
480
    #[inline]
481
    pub fn binary(
33✔
482
        &mut self,
483
        op: BinaryOperator,
484
        left: ExprHandle,
485
        right: ExprHandle,
486
    ) -> ExprHandle {
487
        assert!(left.index() < self.expressions.len());
33✔
488
        assert!(right.index() < self.expressions.len());
33✔
489
        self.push(Expr::Binary { op, left, right })
33✔
490
    }
491

492
    impl_module_binary!(add, Add);
493
    impl_module_binary!(cross, Cross);
494
    impl_module_binary!(distance, Distance);
495
    impl_module_binary!(div, Div);
496
    impl_module_binary!(dot, Dot);
497
    impl_module_binary!(ge, GreaterThanOrEqual);
498
    impl_module_binary!(gt, GreaterThan);
499
    impl_module_binary!(le, LessThanOrEqual);
500
    impl_module_binary!(lt, LessThan);
501
    impl_module_binary!(max, Max);
502
    impl_module_binary!(min, Min);
503
    impl_module_binary!(mul, Mul);
504
    impl_module_binary!(rem, Remainder);
505
    impl_module_binary!(step, Step);
506
    impl_module_binary!(sub, Sub);
507
    impl_module_binary!(uniform, UniformRand);
508
    impl_module_binary!(normal, NormalRand);
509
    impl_module_binary!(vec2, Vec2);
510

511
    /// Build a ternary expression and append it to the module.
512
    ///
513
    /// The handles to the expressions representing the three operands of the
514
    /// ternary operation must be valid, that is reference expressions
515
    /// contained in the current [`Module`].
516
    ///
517
    /// # Panics
518
    ///
519
    /// Panics in some cases if any of the operand handles do not reference
520
    /// existing expressions in the current module. Note however
521
    /// that this check can miss some invalid handles (false negative), so only
522
    /// represents an extra safety net that users shouldn't rely exclusively on
523
    /// to ensure the operand handles are valid. Instead, it's the
524
    /// responsibility of the user to ensure handles reference existing
525
    /// expressions in the current [`Module`].
526
    #[inline]
527
    pub fn ternary(
3✔
528
        &mut self,
529
        op: TernaryOperator,
530
        first: ExprHandle,
531
        second: ExprHandle,
532
        third: ExprHandle,
533
    ) -> ExprHandle {
534
        assert!(first.index() < self.expressions.len());
3✔
535
        assert!(second.index() < self.expressions.len());
3✔
536
        assert!(third.index() < self.expressions.len());
3✔
537
        self.push(Expr::Ternary {
3✔
538
            op,
3✔
539
            first,
3✔
540
            second,
3✔
541
            third,
3✔
542
        })
543
    }
544

545
    impl_module_ternary!(mix, Mix);
546
    impl_module_ternary!(smoothstep, SmoothStep);
547

548
    /// Build a cast expression and append it to the module.
549
    ///
550
    /// The handle to the expressions representing the operand of the cast
551
    /// operation must be valid, that is reference expressions contained in
552
    /// the current [`Module`].
553
    ///
554
    /// # Panics
555
    ///
556
    /// Panics in some cases if the operand handle does not reference existing
557
    /// expressions in the current module. Note however that this check can
558
    /// miss some invalid handles (false negative), so only represents an
559
    /// extra safety net that users shouldn't rely exclusively on
560
    /// to ensure the operand handles are valid. Instead, it's the
561
    /// responsibility of the user to ensure handles reference existing
562
    /// expressions in the current [`Module`].
563
    ///
564
    /// Panics if the resulting cast expression is not valid. See
565
    /// [`CastExpr::is_valid()`] for the exact meaning.
566
    pub fn cast(&mut self, expr: ExprHandle, target: impl Into<ValueType>) -> ExprHandle {
9✔
567
        assert!(expr.index() < self.expressions.len());
9✔
568
        let target = target.into();
9✔
569
        let expr = CastExpr::new(expr, target);
9✔
570
        if let Some(valid) = expr.is_valid(self) {
18✔
571
            assert!(valid);
×
572
        }
573
        self.push(Expr::Cast(expr))
4✔
574
    }
575

576
    /// Get an existing expression from its handle.
577
    #[inline]
578
    pub fn get(&self, expr: ExprHandle) -> Option<&Expr> {
22✔
579
        let index = expr.index();
22✔
580
        self.expressions.get(index)
22✔
581
    }
582

583
    /// Get an existing expression from its handle.
584
    #[inline]
585
    pub fn get_mut(&mut self, expr: ExprHandle) -> Option<&mut Expr> {
2✔
586
        let index = expr.index();
2✔
587
        self.expressions.get_mut(index)
2✔
588
    }
589

590
    /// Get an existing expression from its handle.
591
    #[inline]
592
    pub fn try_get(&self, expr: ExprHandle) -> Result<&Expr, ExprError> {
239✔
593
        let index = expr.index();
239✔
594
        self.expressions
239✔
595
            .get(index)
239✔
596
            .ok_or(ExprError::InvalidExprHandleError(format!(
239✔
597
                "Cannot find expression with handle {:?} in the current module. Check that the Module used to build the expression was the same used in the EvalContext or the original EffectAsset.", expr)))
239✔
598
    }
599

600
    /// Get an existing expression from its handle.
601
    #[inline]
602
    pub fn try_get_mut(&mut self, expr: ExprHandle) -> Result<&mut Expr, ExprError> {
2✔
603
        let index = expr.index();
2✔
604
        self.expressions
2✔
605
            .get_mut(index)
2✔
606
            .ok_or(ExprError::InvalidExprHandleError(format!(
2✔
607
                "Cannot find expression with handle {:?} in the current module. Check that the Module used to build the expression was the same used in the EvalContext or the original EffectAsset.", expr)))
2✔
608
    }
609

610
    /// Is the expression resulting in a compile-time constant which can be
611
    /// hard-coded into a shader's code?
612
    ///
613
    /// # Panics
614
    ///
615
    /// Panics if `expr` doesn't refer to an expression of this module.
616
    #[inline]
617
    pub fn is_const(&self, expr: ExprHandle) -> bool {
×
618
        let expr = self.get(expr).unwrap();
×
619
        expr.is_const(self)
×
620
    }
621

622
    /// Has the expression any side-effect?
623
    ///
624
    /// Expressions with side-effect need to be stored into temporary variables
625
    /// when the shader code is emitted, so that the side effect is only applied
626
    /// once when the expression is reused in multiple locations.
627
    ///
628
    /// # Panics
629
    ///
630
    /// Panics if `expr` doesn't refer to an expression of this module.
631
    pub fn has_side_effect(&self, expr: ExprHandle) -> bool {
×
632
        let expr = self.get(expr).unwrap();
×
633
        expr.has_side_effect(self)
×
634
    }
635

636
    /// Get the texture layout of this module.
637
    pub fn texture_layout(&self) -> TextureLayout {
25✔
638
        self.texture_layout.clone()
25✔
639
    }
640
}
641

642
/// Errors raised when manipulating expressions [`Expr`] and node graphs
643
/// [`Graph`].
644
///
645
/// [`Graph`]: crate::graph::Graph
646
#[derive(Debug, Clone, PartialEq, Eq, Error)]
647
pub enum ExprError {
648
    /// Expression type error.
649
    ///
650
    /// Generally used for invalid type conversion (casting).
651
    #[error("Type error: {0:?}")]
652
    TypeError(String),
653

654
    /// Expression syntax error.
655
    #[error("Syntax error: {0:?}")]
656
    SyntaxError(String),
657

658
    /// Generic graph evaluation error.
659
    #[error("Graph evaluation error: {0:?}")]
660
    GraphEvalError(String),
661

662
    /// Error resolving a property.
663
    ///
664
    /// An unknown property was not defined in the evaluation context, which
665
    /// usually means that the property was not defined with
666
    /// [`Module::add_property()`].
667
    #[error("Property error: {0:?}")]
668
    PropertyError(String),
669

670
    /// Invalid expression handle not referencing any existing [`Expr`] in the
671
    /// evaluation [`Module`].
672
    ///
673
    /// This error is commonly raised when using an [`ExprWriter`] and
674
    /// forgetting to transfer the underlying [`Module`] where the expressions
675
    /// are written to the [`EffectAsset`]. See [`ExprWriter`] for details.
676
    ///
677
    /// [`EffectAsset`]: crate::EffectAsset
678
    #[error("Invalid expression handle: {0:?}")]
679
    InvalidExprHandleError(String),
680

681
    /// Invalid modifier context.
682
    ///
683
    /// The operation was expecting a given [`ModifierContext`], but instead
684
    /// another [`ModifierContext`] was available.
685
    #[error("Invalid modifier context {0}, expected {1} instead.")]
686
    InvalidModifierContext(ModifierContext, ModifierContext),
687
}
688

689
/// Evaluation context for transforming expressions into WGSL code.
690
///
691
/// The evaluation context references a [`Module`] storing all [`Expr`] in use,
692
/// as well as a [`ParticleLayout`] defining the existing attributes of each
693
/// particle and their layout in memory, and a [`PropertyLayout`] defining
694
/// existing properties and their layout in memory. These together define the
695
/// context within which expressions are evaluated.
696
///
697
/// A same expression can be valid in one context and invalid in another. The
698
/// most obvious example is a [`PropertyExpr`] which is only valid if the
699
/// property is actually defined in the property layout of the evaluation
700
/// context.
701
pub trait EvalContext {
702
    /// Get the modifier context of the evaluation.
703
    fn modifier_context(&self) -> ModifierContext;
704

705
    /// Get the particle layout of the effect.
706
    fn particle_layout(&self) -> &ParticleLayout;
707

708
    /// Get the property layout of the effect.
709
    fn property_layout(&self) -> &PropertyLayout;
710

711
    /// Evaluate an expression, returning its WGSL shader code.
712
    ///
713
    /// The evaluation is guaranteed to be unique. Calling `eval()` multiple
714
    /// times with the same handle will return the same result. If the
715
    /// expression referenced by `handle` has side effects, it's evaluated only
716
    /// once on first call, stored in a local variable, and the variable cached
717
    /// and returned on subsequent calls.
718
    fn eval(&mut self, module: &Module, handle: ExprHandle) -> Result<String, ExprError>;
719

720
    /// Generate a unique local variable name.
721
    ///
722
    /// Each time this function is called, a new unique name is generated. The
723
    /// name is guaranteed to be unique within the current evaluation context
724
    /// only. Do not use for global top-level identifiers.
725
    ///
726
    /// The variable name is not registered automatically in the [`Module`]. If
727
    /// you call `make_local_var()` but doesn't use the returned name, it won't
728
    /// appear in the shader.
729
    fn make_local_var(&mut self) -> String;
730

731
    /// Push an intermediate statement during an evaluation.
732
    ///
733
    /// Intermediate statements are inserted before the expression evaluation
734
    /// which produced them. They're generally used to define temporary local
735
    /// variables, for example to store the result of expressions with side
736
    /// effects.
737
    fn push_stmt(&mut self, stmt: &str);
738

739
    /// Create a function.
740
    ///
741
    /// Create a new function with the given `func_name` inside the given
742
    /// [`Module`]. The function takes a list of arguments `args`, which are
743
    /// copied verbatim into the shader code without any validation. The body of
744
    /// the function is generated by invoking the given closure once with the
745
    /// input `module` and a temporary [`EvalContext`] local to the function.
746
    /// The closure must return the generated shader code of the function
747
    /// body. Any statement pushed to the temporary function context with
748
    /// [`EvalContext::push_stmt()`] is emitted inside the function body before
749
    /// the returned code. The function can subsequently be called from the
750
    /// parent context by generating code to call `func_name`, with the correct
751
    /// arguments.
752
    fn make_fn(
753
        &mut self,
754
        func_name: &str,
755
        args: &str,
756
        module: &mut Module,
757
        f: &mut dyn FnMut(&mut Module, &mut dyn EvalContext) -> Result<String, ExprError>,
758
    ) -> Result<(), ExprError>;
759

760
    /// Check if the particle attribute struct is a pointer?
761
    ///
762
    /// In some context the attribute struct (named 'particle' in WGSL code) is
763
    /// a pointer instead of being a struct instance. This happens in particular
764
    /// when defining a function for a modifier, and passing the attribute
765
    /// struct to be modified. In that case the generated code needs to emit
766
    /// a pointer indirection code to access the fields of the struct.
767
    fn is_attribute_pointer(&self) -> bool;
768
}
769

770
/// Language expression producing a value.
771
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
772
pub enum Expr {
773
    /// Built-in expression ([`BuiltInExpr`]).
774
    ///
775
    /// A built-in expression provides access to some internal
776
    /// quantities like the simulation time.
777
    BuiltIn(BuiltInExpr),
778

779
    /// Literal expression ([`LiteralExpr`]).
780
    ///
781
    /// A literal expression represents a shader constants.
782
    Literal(LiteralExpr),
783

784
    /// Property expression ([`PropertyExpr`]).
785
    ///
786
    /// A property expression represents the value of an [`EffectAsset`]'s
787
    /// property.
788
    ///
789
    /// [`EffectAsset`]: crate::EffectAsset
790
    Property(PropertyExpr),
791

792
    /// Attribute expression ([`AttributeExpr`]).
793
    ///
794
    /// An attribute expression represents the value of an attribute for a
795
    /// particle, like its position or velocity.
796
    Attribute(AttributeExpr),
797

798
    /// Unary operation expression.
799
    ///
800
    /// A unary operation transforms an expression into another expression.
801
    Unary {
802
        /// Unary operator.
803
        op: UnaryOperator,
804
        /// Operand the unary operation applies to.
805
        expr: ExprHandle,
806
    },
807

808
    /// Binary operation expression.
809
    ///
810
    /// A binary operation composes two expressions into a third one.
811
    Binary {
812
        /// Binary operator.
813
        op: BinaryOperator,
814
        /// Left-hand side operand the binary operation applies to.
815
        left: ExprHandle,
816
        /// Right-hand side operand the binary operation applies to.
817
        right: ExprHandle,
818
    },
819

820
    /// Ternary operation expression.
821
    ///
822
    /// A ternary operation composes three expressions into a fourth one.
823
    Ternary {
824
        /// Ternary operator.
825
        op: TernaryOperator,
826
        /// First operand the ternary operation applies to.
827
        first: ExprHandle,
828
        /// Second operand the ternary operation applies to.
829
        second: ExprHandle,
830
        /// Third operand the ternary operation applies to.
831
        third: ExprHandle,
832
    },
833

834
    /// Cast expression.
835
    ///
836
    /// An expression to cast an expression to another type.
837
    Cast(CastExpr),
838

839
    /// Access to textures.
840
    ///
841
    /// An expression to sample a texture from the effect's material. Currently
842
    /// only color textures (returning a `vec4<f32>`) are supported.
843
    TextureSample(TextureSampleExpr),
844
}
845

846
impl Expr {
847
    /// Is the expression resulting in a compile-time constant which can be
848
    /// hard-coded into a shader's code?
849
    ///
850
    /// The [`Module`] passed as argument is the owning module of the
851
    /// expression, which is used to recursively evaluate the const-ness of the
852
    /// entire expression. For some expressions like literals or attributes or
853
    /// properties their const-ness is intrinsic to the expression type, but for
854
    /// other expressions like binary operations (addition, ...) their
855
    /// const-ness depends in turn on the const-ness of their sub-expressions
856
    /// (left and right operands), which requires a [`Module`] to be retrieved
857
    /// and evaluated.
858
    ///
859
    /// # Example
860
    ///
861
    /// ```
862
    /// # use bevy_hanabi::*;
863
    /// # let mut module = Module::default();
864
    /// // Literals are always constant by definition.
865
    /// assert!(Expr::Literal(LiteralExpr::new(1.)).is_const(&module));
866
    ///
867
    /// // Properties and attributes are never constant, since they're by definition used
868
    /// // to provide runtime customization.
869
    /// let prop = module.add_property("my_property", 3.0.into());
870
    /// assert!(!Expr::Property(PropertyExpr::new(prop)).is_const(&module));
871
    /// assert!(!Expr::Attribute(AttributeExpr::new(Attribute::POSITION)).is_const(&module));
872
    /// ```
873
    pub fn is_const(&self, module: &Module) -> bool {
×
874
        match self {
×
875
            Expr::BuiltIn(expr) => expr.is_const(),
×
876
            Expr::Literal(expr) => expr.is_const(),
×
877
            Expr::Property(expr) => expr.is_const(),
×
878
            Expr::Attribute(expr) => expr.is_const(),
×
879
            Expr::Unary { expr, .. } => module.is_const(*expr),
×
880
            Expr::Binary { left, right, .. } => module.is_const(*left) && module.is_const(*right),
×
881
            Expr::Ternary {
882
                first,
×
883
                second,
×
884
                third,
×
885
                ..
×
886
            } => module.is_const(*first) && module.is_const(*second) && module.is_const(*third),
×
887
            Expr::Cast(expr) => module.is_const(expr.inner),
×
888
            Expr::TextureSample(_) => false,
×
889
        }
890
    }
891

892
    /// Has the expression any side-effect?
893
    ///
894
    /// Expressions with side-effect need to be stored into temporary variables
895
    /// when the shader code is emitted, so that the side effect is only applied
896
    /// once when the expression is reused in multiple locations.
897
    pub fn has_side_effect(&self, module: &Module) -> bool {
×
898
        match self {
×
899
            Expr::BuiltIn(expr) => expr.has_side_effect(),
×
900
            Expr::Literal(_) => false,
×
901
            Expr::Property(_) => false,
×
902
            Expr::Attribute(_) => false,
×
903
            Expr::Unary { expr, .. } => module.has_side_effect(*expr),
×
904
            Expr::Binary { left, right, op } => {
×
NEW
905
                (*op == BinaryOperator::UniformRand || *op == BinaryOperator::NormalRand)
×
906
                    || module.has_side_effect(*left)
×
907
                    || module.has_side_effect(*right)
×
908
            }
909
            Expr::Ternary {
910
                first,
×
911
                second,
×
912
                third,
×
913
                ..
×
914
            } => {
×
915
                module.has_side_effect(*first)
×
916
                    || module.has_side_effect(*second)
×
917
                    || module.has_side_effect(*third)
×
918
            }
919
            Expr::Cast(expr) => module.has_side_effect(expr.inner),
×
920
            Expr::TextureSample(_) => false,
×
921
        }
922
    }
923

924
    /// The type of the value produced by the expression.
925
    ///
926
    /// If the type is variable and depends on the runtime evaluation context,
927
    /// this returns `None`. In that case the type needs to be obtained by
928
    /// evaluating the expression with [`eval()`].
929
    ///
930
    /// # Example
931
    ///
932
    /// ```
933
    /// # use bevy_hanabi::*;
934
    /// // Literal expressions always have a constant, build-time value type.
935
    /// let expr = Expr::Literal(LiteralExpr::new(1.));
936
    /// assert_eq!(
937
    ///     expr.value_type(),
938
    ///     Some(ValueType::Scalar(ScalarType::Float))
939
    /// );
940
    /// ```
941
    ///
942
    /// [`eval()`]: crate::graph::Expr::eval
943
    pub fn value_type(&self) -> Option<ValueType> {
12✔
944
        match self {
12✔
945
            Expr::BuiltIn(expr) => Some(expr.value_type()),
×
946
            Expr::Literal(expr) => Some(expr.value_type()),
8✔
947
            Expr::Property(_) => None,
1✔
948
            Expr::Attribute(expr) => Some(expr.value_type()),
3✔
949
            Expr::Unary { .. } => None,
×
950
            Expr::Binary { .. } => None,
×
951
            Expr::Ternary { .. } => None,
×
952
            Expr::Cast(expr) => Some(expr.value_type()),
×
953
            Expr::TextureSample(expr) => Some(expr.value_type()),
×
954
        }
955
    }
956

957
    /// Evaluate the expression in the given context.
958
    ///
959
    /// Evaluate the full expression as part of the given evaluation context,
960
    /// returning the WGSL string representation of the expression on success.
961
    ///
962
    /// The evaluation context is used to resolve some quantities related to the
963
    /// effect asset, like its properties. It also holds the [`Module`] that the
964
    /// expression is part of, to allow resolving sub-expressions of operators.
965
    ///
966
    /// # Example
967
    ///
968
    /// ```
969
    /// # use bevy_hanabi::*;
970
    /// let mut module = Module::default();
971
    /// # let pl = PropertyLayout::empty();
972
    /// # let pal = ParticleLayout::default();
973
    /// # let mut context = ShaderWriter::new(ModifierContext::Update, &pl, &pal);
974
    /// let handle = module.lit(1.);
975
    /// let expr = module.get(handle).unwrap();
976
    /// assert_eq!(Ok("1.".to_string()), expr.eval(&module, &mut context));
977
    /// ```
978
    pub fn eval(
237✔
979
        &self,
980
        module: &Module,
981
        context: &mut dyn EvalContext,
982
    ) -> Result<String, ExprError> {
983
        match self {
237✔
984
            Expr::BuiltIn(expr) => expr.eval(context),
34✔
985
            Expr::Literal(expr) => expr.eval(context),
96✔
986
            Expr::Property(expr) => expr.eval(module, context),
2✔
987
            Expr::Attribute(expr) => expr.eval(context),
26✔
988
            Expr::Unary { op, expr } => {
34✔
989
                // Recursively evaluate child expressions throught the context to ensure caching
990
                let expr = context.eval(module, *expr)?;
68✔
991

992
                // if expr.value_type() != self.value_type() {
993
                //     return Err(ExprError::TypeError(format!(
994
                //         "Cannot apply normalize() function to non-vector expression: {}",
995
                //         expr.unwrap_or("(error evaluating expression)".to_string())
996
                //     )));
997
                // }
998

999
                Ok(if op.is_functional() {
1000
                    format!("{}({})", op.to_wgsl_string(), expr)
30✔
1001
                } else {
1002
                    format!("{}.{}", expr, op.to_wgsl_string())
4✔
1003
                })
1004
            }
1005
            Expr::Binary { op, left, right } => {
38✔
1006
                // Recursively evaluate child expressions throught the context to ensure caching
1007
                let compiled_left = context.eval(module, *left)?;
76✔
1008
                let compiled_right = context.eval(module, *right)?;
38✔
1009

1010
                // if !self.input.value_type().is_vector() {
1011
                //     return Err(ExprError::TypeError(format!(
1012
                //         "Cannot apply normalize() function to non-vector expression: {}",
1013
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1014
                //     )));
1015
                // }
1016

1017
                if op.is_functional() {
1018
                    if op.needs_type_suffix() {
11✔
1019
                        let lhs_type = module.get(*left).and_then(|arg| arg.value_type());
×
1020
                        let rhs_type = module.get(*right).and_then(|arg| arg.value_type());
×
1021
                        if lhs_type.is_none() || rhs_type.is_none() {
×
1022
                            return Err(ExprError::TypeError(
×
1023
                                "Can't determine the type of the operand".to_string(),
×
1024
                            ));
1025
                        }
1026
                        if lhs_type != rhs_type {
×
1027
                            return Err(ExprError::TypeError("Mismatched types".to_string()));
×
1028
                        }
1029
                        let value_type = lhs_type.unwrap();
×
1030
                        let suffix = match value_type {
×
1031
                            ValueType::Scalar(ScalarType::Float) => "f",
×
1032
                            ValueType::Vector(vector_type)
×
1033
                                if vector_type.elem_type() == ScalarType::Float =>
×
1034
                            {
1035
                                match vector_type.count() {
1036
                                    2 => "vec2",
×
1037
                                    3 => "vec3",
×
1038
                                    4 => "vec4",
×
1039
                                    _ => unreachable!(),
1040
                                }
1041
                            }
1042
                            _ => {
1043
                                // Add more types here as needed.
1044
                                return Err(ExprError::TypeError("Unsupported type".to_string()));
×
1045
                            }
1046
                        };
1047

1048
                        Ok(format!(
1049
                            "{}_{}({}, {})",
1050
                            op.to_wgsl_string(),
1051
                            suffix,
1052
                            compiled_left,
1053
                            compiled_right
1054
                        ))
1055
                    } else {
1056
                        Ok(format!(
11✔
1057
                            "{}({}, {})",
11✔
1058
                            op.to_wgsl_string(),
11✔
1059
                            compiled_left,
11✔
1060
                            compiled_right
11✔
1061
                        ))
1062
                    }
1063
                } else {
1064
                    Ok(format!(
27✔
1065
                        "({}) {} ({})",
27✔
1066
                        compiled_left,
27✔
1067
                        op.to_wgsl_string(),
27✔
1068
                        compiled_right
27✔
1069
                    ))
1070
                }
1071
            }
1072
            Expr::Ternary {
1073
                op,
3✔
1074
                first,
3✔
1075
                second,
3✔
1076
                third,
3✔
1077
            } => {
1078
                // Recursively evaluate child expressions throught the context to ensure caching
1079
                let first = context.eval(module, *first)?;
6✔
1080
                let second = context.eval(module, *second)?;
3✔
1081
                let third = context.eval(module, *third)?;
3✔
1082

1083
                // if !self.input.value_type().is_vector() {
1084
                //     return Err(ExprError::TypeError(format!(
1085
                //         "Cannot apply normalize() function to non-vector expression: {}",
1086
                //         expr.unwrap_or("(error evaluating expression)".to_string())
1087
                //     )));
1088
                // }
1089

1090
                Ok(format!(
3✔
1091
                    "{}({}, {}, {})",
3✔
1092
                    op.to_wgsl_string(),
3✔
1093
                    first,
3✔
1094
                    second,
3✔
1095
                    third
3✔
1096
                ))
1097
            }
1098
            Expr::Cast(expr) => {
4✔
1099
                // Recursively evaluate child expressions throught the context to ensure caching
1100
                let inner = context.eval(module, expr.inner)?;
8✔
1101

1102
                Ok(format!("{}({})", expr.target.to_wgsl_string(), inner))
4✔
1103
            }
1104
            Expr::TextureSample(expr) => expr.eval(module, context),
×
1105
        }
1106
    }
1107
}
1108

1109
/// A literal constant expression like `3.0` or `vec3<f32>(1.0, 2.0, 3.0)`.
1110
///
1111
/// Literal expression are compile-time constants. They are always constant
1112
/// ([`is_const()`] is `true`) and have a value type equal to the type of the
1113
/// constant itself.
1114
///
1115
/// [`is_const()`]: LiteralExpr::is_const
1116
#[derive(Debug, Clone, Copy, PartialEq, Hash, Reflect, Serialize, Deserialize)]
1117
#[serde(transparent)]
1118
pub struct LiteralExpr {
1119
    value: Value,
1120
}
1121

1122
impl LiteralExpr {
1123
    /// Create a new literal expression from a [`Value`].
1124
    pub fn new<V>(value: V) -> Self
74✔
1125
    where
1126
        Value: From<V>,
1127
    {
1128
        Self {
1129
            value: value.into(),
74✔
1130
        }
1131
    }
1132

1133
    /// Is the expression resulting in a compile-time constant which can be
1134
    /// hard-coded into a shader's code?
1135
    pub fn is_const(&self) -> bool {
×
1136
        true
×
1137
    }
1138

1139
    /// Get the value type of the expression.
1140
    pub fn value_type(&self) -> ValueType {
8✔
1141
        self.value.value_type()
8✔
1142
    }
1143

1144
    /// Evaluate the expression in the given context.
1145
    pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
96✔
1146
        Ok(self.value.to_wgsl_string())
96✔
1147
    }
1148
}
1149

1150
impl ToWgslString for LiteralExpr {
1151
    fn to_wgsl_string(&self) -> String {
×
1152
        self.value.to_wgsl_string()
×
1153
    }
1154
}
1155

1156
impl From<&Value> for LiteralExpr {
1157
    fn from(value: &Value) -> Self {
×
1158
        Self { value: *value }
×
1159
    }
1160
}
1161

1162
impl<T: Into<Value>> From<T> for LiteralExpr {
1163
    fn from(value: T) -> Self {
×
1164
        Self {
1165
            value: value.into(),
×
1166
        }
1167
    }
1168
}
1169

1170
/// Expression representing the value of an attribute of a particle.
1171
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1172
pub struct AttributeExpr {
1173
    attr: Attribute,
1174
}
1175

1176
impl AttributeExpr {
1177
    /// Create a new attribute expression.
1178
    #[inline]
1179
    pub fn new(attr: Attribute) -> Self {
27✔
1180
        Self { attr }
1181
    }
1182

1183
    /// Is the expression resulting in a compile-time constant which can be
1184
    /// hard-coded into a shader's code?
1185
    pub fn is_const(&self) -> bool {
×
1186
        false
×
1187
    }
1188

1189
    /// Get the value type of the expression.
1190
    pub fn value_type(&self) -> ValueType {
3✔
1191
        self.attr.value_type()
3✔
1192
    }
1193

1194
    /// Evaluate the expression in the given context.
1195
    pub fn eval(&self, context: &dyn EvalContext) -> Result<String, ExprError> {
26✔
1196
        if context.is_attribute_pointer() {
26✔
1197
            Ok(format!("(*particle).{}", self.attr.name()))
2✔
1198
        } else {
1199
            Ok(format!("particle.{}", self.attr.name()))
24✔
1200
        }
1201
    }
1202
}
1203

1204
impl ToWgslString for AttributeExpr {
1205
    fn to_wgsl_string(&self) -> String {
×
1206
        format!("particle.{}", self.attr.name())
×
1207
    }
1208
}
1209

1210
impl From<Attribute> for AttributeExpr {
1211
    fn from(value: Attribute) -> Self {
×
1212
        AttributeExpr::new(value)
×
1213
    }
1214
}
1215

1216
/// Expression representing the value of a property of an effect.
1217
///
1218
/// A property expression represents the value of the property at the time the
1219
/// expression appears. In shader, the expression yields a read from the
1220
/// property memory location.
1221
///
1222
/// To create a property to reference with an expression, use
1223
/// [`Module::add_property()`].
1224
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1225
#[repr(transparent)]
1226
#[serde(transparent)]
1227
pub struct PropertyExpr {
1228
    property: PropertyHandle,
1229
}
1230

1231
impl PropertyExpr {
1232
    /// Create a new property expression.
1233
    #[inline]
1234
    pub fn new(property: PropertyHandle) -> Self {
4✔
1235
        Self { property }
1236
    }
1237

1238
    /// Is the expression resulting in a compile-time constant which can be
1239
    /// hard-coded into a shader's code?
1240
    fn is_const(&self) -> bool {
×
1241
        false
×
1242
    }
1243

1244
    /// Evaluate the expression in the given context.
1245
    fn eval(&self, module: &Module, context: &dyn EvalContext) -> Result<String, ExprError> {
2✔
1246
        let prop = module
4✔
1247
            .get_property(self.property)
2✔
1248
            .ok_or(ExprError::PropertyError(format!(
2✔
1249
                "Unknown property handle {:?} in evaluation module.",
2✔
1250
                self.property
2✔
1251
            )))?;
1252
        if !context.property_layout().contains(prop.name()) {
1253
            return Err(ExprError::PropertyError(format!(
×
1254
                "Unknown property '{}' in evaluation layout.",
×
1255
                prop.name()
×
1256
            )));
1257
        }
1258

1259
        Ok(format!("properties.{}", prop.name()))
2✔
1260
    }
1261
}
1262

1263
/// Expression to cast an expression to another type.
1264
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1265
pub struct CastExpr {
1266
    /// The operand expression to cast.
1267
    inner: ExprHandle,
1268
    /// The target type to cast to.
1269
    target: ValueType,
1270
}
1271

1272
impl CastExpr {
1273
    /// Create a new cast expression.
1274
    #[inline]
1275
    pub fn new(inner: ExprHandle, target: impl Into<ValueType>) -> Self {
12✔
1276
        Self {
1277
            inner,
1278
            target: target.into(),
12✔
1279
        }
1280
    }
1281

1282
    /// Get the value type of the expression.
1283
    pub fn value_type(&self) -> ValueType {
3✔
1284
        self.target
3✔
1285
    }
1286

1287
    /// Try to evaluate if the cast expression is valid.
1288
    ///
1289
    /// The evaluation fails if the value type of the operand cannot be
1290
    /// determined. In that case, the function returns `None`.
1291
    ///
1292
    /// Valid cast expressions are:
1293
    /// - scalar to scalar
1294
    /// - scalar to vector
1295
    /// - vector to vector
1296
    /// - matrix to matrix
1297
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
12✔
1298
        let Some(inner) = module.get(self.inner) else {
24✔
1299
            return Some(false);
×
1300
        };
1301
        if let Some(inner_type) = inner.value_type() {
11✔
1302
            match self.target {
1303
                ValueType::Scalar(_) => {
1304
                    // scalar -> scalar only
1305
                    Some(matches!(inner_type, ValueType::Scalar(_)))
8✔
1306
                }
1307
                ValueType::Vector(_) => {
1308
                    // {scalar, vector} -> vector
1309
                    Some(!matches!(inner_type, ValueType::Matrix(_)))
7✔
1310
                }
1311
                ValueType::Matrix(_) => {
1312
                    // matrix -> matrix only
1313
                    Some(matches!(inner_type, ValueType::Matrix(_)))
4✔
1314
                }
1315
            }
1316
        } else {
1317
            None
1✔
1318
        }
1319
    }
1320
}
1321

1322
/// Expression to sample a texture from the effect's material.
1323
///
1324
/// This currently supports only color textures, that is all textures which
1325
/// return a `vec4<f32>` when sampled. So this excludes depth textures, but
1326
/// includes single-channel (e.g. red) textures. See the WGSL specification for
1327
/// details.
1328
///
1329
/// This currently only samples with `textureSample()`.
1330
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1331
pub struct TextureSampleExpr {
1332
    /// The index of the image to sample. This is the texture slot defined in
1333
    /// the [`Module`]. The texture bound to the slot is defined in the
1334
    /// [`EffectMaterial`] component.
1335
    ///
1336
    /// [`EffectMaterial`]: crate::EffectMaterial
1337
    pub image: ExprHandle,
1338
    /// The coordinates to sample at.
1339
    pub coordinates: ExprHandle,
1340
}
1341

1342
impl TextureSampleExpr {
1343
    /// Create a new texture sample expression.
1344
    #[inline]
1345
    pub fn new(image: ExprHandle, coordinates: ExprHandle) -> Self {
×
1346
        Self { image, coordinates }
1347
    }
1348

1349
    /// Get the value type of the expression.
1350
    pub fn value_type(&self) -> ValueType {
×
1351
        // FIXME - depth textures return a single f32 when sampled
1352
        ValueType::Vector(VectorType::VEC4F)
×
1353
    }
1354

1355
    /// Try to evaluate if the texture sample expression is valid.
1356
    ///
1357
    /// This only checks that the expressions exist in the module.
1358
    pub fn is_valid(&self, module: &Module) -> Option<bool> {
×
1359
        let Some(_image) = module.get(self.image) else {
×
1360
            return Some(false);
×
1361
        };
1362
        let Some(_coordinates) = module.get(self.coordinates) else {
×
1363
            return Some(false);
×
1364
        };
1365
        Some(true)
×
1366
    }
1367

1368
    /// Evaluate the expression in the given context.
1369
    pub fn eval(
×
1370
        &self,
1371
        module: &Module,
1372
        context: &mut dyn EvalContext,
1373
    ) -> Result<String, ExprError> {
1374
        let image = module.try_get(self.image)?;
×
1375
        let image = image.eval(module, context)?;
×
1376
        let coordinates = module.try_get(self.coordinates)?;
×
1377
        let coordinates = coordinates.eval(module, context)?;
×
1378
        Ok(format!(
×
1379
            "textureSample(material_texture_{image}, material_sampler_{image}, {coordinates})",
×
1380
        ))
1381
    }
1382
}
1383

1384
/// Built-in operators.
1385
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1386
pub enum BuiltInOperator {
1387
    /// Current effect system simulation time since startup, in seconds.
1388
    ///
1389
    /// This is based on the
1390
    /// [`Time<EffectSimulation>`](crate::time::EffectSimulation) clock.
1391
    ///
1392
    /// Type: `f32`
1393
    Time,
1394
    /// Delta time, in seconds, since last effect system update.
1395
    ///
1396
    /// Type: `f32`
1397
    DeltaTime,
1398
    /// Current virtual time since startup, in seconds.
1399
    ///
1400
    /// This is based on the [`Time<Virtual>`](bevy::time::Virtual) clock.
1401
    ///
1402
    /// Type: `f32`
1403
    VirtualTime,
1404
    /// Virtual delta time, in seconds, since last effect system update.
1405
    ///
1406
    /// Type: `f32`
1407
    VirtualDeltaTime,
1408
    /// Current real time since startup, in seconds.
1409
    ///
1410
    /// This is based on the [`Time<Time>`](bevy::time::Real) clock.
1411
    ///
1412
    /// Type: `f32`
1413
    RealTime,
1414
    /// Real delta time, in seconds, since last effect system update.
1415
    ///
1416
    /// Type: `f32`
1417
    RealDeltaTime,
1418
    /// Random unit value of the given type.
1419
    ///
1420
    /// The type can be any scalar or vector type. Matrix types are not
1421
    /// supported. The random values generated are uniformly distributed in
1422
    /// `[0:1]`. For vectors, each component is sampled separately.
1423
    ///
1424
    /// The random number generator is from [the PCG family] of PRNGs, and is
1425
    /// implemented directly inside the shader, and running on the GPU
1426
    /// exclusively. It's seeded by the [`Spawner`].
1427
    ///
1428
    /// Type: Same as its [`ValueType`].
1429
    ///
1430
    /// [the PCG family]: https://www.pcg-random.org/
1431
    /// [`Spawner`]: crate::Spawner
1432
    Rand(ValueType),
1433
    /// Value of the alpha cutoff for alpha masking.
1434
    ///
1435
    /// This value is only available in the render context. It represents the
1436
    /// current threshold, generally in \[0:1\], which the particle's fragment
1437
    /// alpha value will be compared against to determine alpha masking.
1438
    ///
1439
    /// The value is initalized at the beginning of the fragment shader to the
1440
    /// expression stored in [`AlphaMode::Mask`].
1441
    ///
1442
    /// Type: `f32`
1443
    ///
1444
    /// [`AlphaMode::Mask`]: crate::AlphaMode::Mask
1445
    AlphaCutoff,
1446
    /// Alive flag for the particle.
1447
    ///
1448
    /// The alive flag is initialized at the beginning of the update pass:
1449
    /// - If the particle has both the [`Attribute::AGE`] and
1450
    ///   [`Attribute::LIFETIME`], then the initial value at the beginning of
1451
    ///   the update pass is `age < lifetime`.
1452
    /// - Otherwise, the initial value is `true`.
1453
    ///
1454
    /// At the end of the update pass, if the particle has both the
1455
    /// [`Attribute::AGE`] and   [`Attribute::LIFETIME`], then the flag is
1456
    /// re-evaluated as:
1457
    ///
1458
    /// ```wgsl
1459
    /// is_alive = is_alive && (particle.age < particle.lifetime);
1460
    /// ```
1461
    ///
1462
    /// If the flag is `false` after that, the particle is considered dead and
1463
    /// it's deallocated.
1464
    ///
1465
    /// This flag is only available in the update pass. Attempting to use it
1466
    /// inside either the init or render passes will generate an invalid shader.
1467
    ///
1468
    /// Type: `bool`
1469
    IsAlive,
1470
}
1471

1472
impl BuiltInOperator {
1473
    /// Get the operator name.
1474
    pub fn name(&self) -> &str {
49✔
1475
        match self {
49✔
1476
            BuiltInOperator::Time => "time",
6✔
1477
            BuiltInOperator::DeltaTime => "delta_time",
13✔
1478
            BuiltInOperator::VirtualTime => "virtual_time",
2✔
1479
            BuiltInOperator::VirtualDeltaTime => "virtual_delta_time",
2✔
1480
            BuiltInOperator::RealTime => "real_time",
2✔
1481
            BuiltInOperator::RealDeltaTime => "real_delta_time",
2✔
1482
            BuiltInOperator::Rand(value_type) => match value_type {
22✔
1483
                ValueType::Scalar(s) => match s {
10✔
1484
                    ScalarType::Bool => "brand",
1✔
1485
                    ScalarType::Float => "frand",
7✔
1486
                    ScalarType::Int => "irand",
1✔
1487
                    ScalarType::Uint => "urand",
1✔
1488
                },
1489
                ValueType::Vector(vector_type) => {
12✔
1490
                    match (vector_type.elem_type(), vector_type.count()) {
12✔
1491
                        (ScalarType::Bool, 2) => "brand2",
1✔
1492
                        (ScalarType::Bool, 3) => "brand3",
1✔
1493
                        (ScalarType::Bool, 4) => "brand4",
1✔
1494
                        (ScalarType::Float, 2) => "frand2",
1✔
1495
                        (ScalarType::Float, 3) => "frand3",
1✔
1496
                        (ScalarType::Float, 4) => "frand4",
1✔
1497
                        (ScalarType::Int, 2) => "irand2",
1✔
1498
                        (ScalarType::Int, 3) => "irand3",
1✔
1499
                        (ScalarType::Int, 4) => "irand4",
1✔
1500
                        (ScalarType::Uint, 2) => "urand2",
1✔
1501
                        (ScalarType::Uint, 3) => "urand3",
1✔
1502
                        (ScalarType::Uint, 4) => "urand4",
1✔
1503
                        _ => panic!("Invalid vector type {:?}", vector_type),
×
1504
                    }
1505
                }
1506
                ValueType::Matrix(_) => panic!("Invalid BuiltInOperator::Rand(ValueType::Matrix)."),
×
1507
            },
1508
            BuiltInOperator::AlphaCutoff => "alpha_cutoff",
×
1509
            BuiltInOperator::IsAlive => "is_alive",
×
1510
        }
1511
    }
1512

1513
    /// Get the type of the value of a built-in operator.
1514
    pub fn value_type(&self) -> ValueType {
4✔
1515
        match self {
4✔
1516
            BuiltInOperator::Time => ValueType::Scalar(ScalarType::Float),
2✔
1517
            BuiltInOperator::DeltaTime => ValueType::Scalar(ScalarType::Float),
2✔
1518
            BuiltInOperator::VirtualTime => ValueType::Scalar(ScalarType::Float),
×
1519
            BuiltInOperator::VirtualDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1520
            BuiltInOperator::RealTime => ValueType::Scalar(ScalarType::Float),
×
1521
            BuiltInOperator::RealDeltaTime => ValueType::Scalar(ScalarType::Float),
×
1522
            BuiltInOperator::Rand(value_type) => *value_type,
×
1523
            BuiltInOperator::AlphaCutoff => ValueType::Scalar(ScalarType::Float),
×
1524
            BuiltInOperator::IsAlive => ValueType::Scalar(ScalarType::Bool),
×
1525
        }
1526
    }
1527

1528
    // /// Evaluate the result of the operator as an expression.
1529
    // pub fn eval(&self, _context: &dyn EvalContext) -> Result<String, ExprError> {
1530
    //     match self {
1531
    //         BuiltInOperator::Time => Value::Scalar(Scal)
1532
    //     }
1533
    // }
1534
}
1535

1536
impl ToWgslString for BuiltInOperator {
1537
    fn to_wgsl_string(&self) -> String {
37✔
1538
        match self {
37✔
1539
            BuiltInOperator::Rand(_) => format!("{}()", self.name()),
22✔
1540
            BuiltInOperator::IsAlive => "is_alive".to_string(),
1✔
1541
            _ => format!("sim_params.{}", self.name()),
14✔
1542
        }
1543
    }
1544
}
1545

1546
/// Expression for getting built-in quantities related to the effect system.
1547
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1548
pub struct BuiltInExpr {
1549
    operator: BuiltInOperator,
1550
}
1551

1552
impl BuiltInExpr {
1553
    /// Create a new built-in operator expression.
1554
    ///
1555
    /// # Panics
1556
    ///
1557
    /// Panics on invalid [`BuiltInOperator`], like `Rand(MatrixType)`. See
1558
    /// each [`BuiltInOperator`] variant for more details.
1559
    #[inline]
1560
    pub fn new(operator: BuiltInOperator) -> Self {
33✔
1561
        if let BuiltInOperator::Rand(value_type) = operator {
51✔
1562
            assert!(!matches!(value_type, ValueType::Matrix(_)));
18✔
1563
        }
1564
        Self { operator }
1565
    }
1566

1567
    /// Is the expression resulting in a compile-time constant?
1568
    ///
1569
    /// Constant expressions can be hard-coded into a shader's code, making them
1570
    /// more efficient and open to shader compiler optimizing.
1571
    pub fn is_const(&self) -> bool {
×
1572
        false
×
1573
    }
1574

1575
    /// Has the expression any side-effect?
1576
    ///
1577
    /// Expressions with side-effect need to be stored into temporary variables
1578
    /// when the shader code is emitted, so that the side effect is only applied
1579
    /// once when the expression is reused in multiple locations.
1580
    pub fn has_side_effect(&self) -> bool {
37✔
1581
        matches!(self.operator, BuiltInOperator::Rand(_))
52✔
1582
    }
1583

1584
    /// Get the value type of the expression.
1585
    ///
1586
    /// The value type of the expression is the type of the value(s) that an
1587
    /// expression produces.
1588
    pub fn value_type(&self) -> ValueType {
×
1589
        self.operator.value_type()
×
1590
    }
1591

1592
    /// Evaluate the expression in the given context.
1593
    pub fn eval(&self, context: &mut dyn EvalContext) -> Result<String, ExprError> {
37✔
1594
        if self.has_side_effect() {
37✔
1595
            let var_name = context.make_local_var();
22✔
1596
            context.push_stmt(&format!("let {} = {};", var_name, self.to_wgsl_string()));
22✔
1597
            Ok(var_name)
22✔
1598
        } else {
1599
            Ok(self.to_wgsl_string())
15✔
1600
        }
1601
    }
1602
}
1603

1604
impl ToWgslString for BuiltInExpr {
1605
    fn to_wgsl_string(&self) -> String {
37✔
1606
        self.operator.to_wgsl_string()
37✔
1607
    }
1608
}
1609

1610
/// Unary operator.
1611
///
1612
/// Operator applied to a single operand to produce another value. The type of
1613
/// the operand and the result are not necessarily the same. Valid operand types
1614
/// depend on the operator itself.
1615
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1616
pub enum UnaryOperator {
1617
    /// Absolute value operator.
1618
    ///
1619
    /// Return the absolute value of the operand, component-wise for vectors.
1620
    /// Only valid for numeric operands.
1621
    Abs,
1622

1623
    /// Logical ALL operator for bool vectors.
1624
    ///
1625
    /// Return `true` if all the components of the bool vector operand are
1626
    /// `true`. Invalid for any other type of operand.
1627
    All,
1628

1629
    /// Logical ANY operator for bool vectors.
1630
    ///
1631
    /// Return `true` if any component of the bool vector operand is `true`.
1632
    /// Invalid for any other type of operand.
1633
    Any,
1634

1635
    /// Ceiling operator.
1636
    ///
1637
    /// Return the unique integral number `k` such that `k-1 < x <= k`, where
1638
    /// `x` is the operand which the operator applies to.
1639
    Ceil,
1640

1641
    /// Cosine operator.
1642
    Cos,
1643

1644
    /// Natural exponent operator.
1645
    ///
1646
    /// Return the natural exponentiation of the operand (`e^x`), component-wise
1647
    /// for vectors.
1648
    Exp,
1649

1650
    /// Base-2 exponent operator.
1651
    ///
1652
    /// Return two raised to the power of the operand (`2^x`), component-wise
1653
    /// for vectors.
1654
    Exp2,
1655

1656
    /// Floor operator.
1657
    ///
1658
    /// Return the unique integral number `k` such that `k <= x < k+1`, where
1659
    /// `x` is the operand which the operator applies to.
1660
    Floor,
1661

1662
    /// Fractional part operator.
1663
    ///
1664
    /// Return the fractional part of the operand, which is equal to `x -
1665
    /// floor(x)`, component-wise for vectors.
1666
    Fract,
1667

1668
    /// Inverse square root operator.
1669
    ///
1670
    /// Return the inverse square root of the floating-point operand (`1.0 /
1671
    /// sqrt(x)`), component-wise for vectors.
1672
    InvSqrt,
1673

1674
    /// Length operator.
1675
    ///
1676
    /// Return the length of a floating point scalar or vector. The "length" of
1677
    /// a scalar is taken as its absolute value. The length of a vector is the
1678
    /// Euclidian distance `sqrt(x^2 + ...)` (square root of the sum of the
1679
    /// squared components).
1680
    ///
1681
    /// The output is always a floating point scalar.
1682
    Length,
1683

1684
    /// Natural logarithm operator.
1685
    ///
1686
    /// Return the natural logarithm of the operand (`log(x)`), component-wise
1687
    /// for vectors.
1688
    Log,
1689

1690
    /// Base-2 logarithm operator.
1691
    ///
1692
    /// Return the base-2 logarithm of the operand (`log2(x)`), component-wise
1693
    /// for vectors.
1694
    Log2,
1695

1696
    /// Vector normalizing operator.
1697
    ///
1698
    /// Normalize the given numeric vector. Only valid for numeric vector
1699
    /// operands.
1700
    Normalize,
1701

1702
    /// Packing operator from `vec4<f32>` to `u32` (signed normalized).
1703
    ///
1704
    /// Convert the four components of a signed normalized floating point vector
1705
    /// into a signed integral `i8` value in `[-128:127]`, then pack those
1706
    /// four values into a single `u32`. Each vector component should be in
1707
    /// `[-1:1]` before packing; values outside this range are clamped.
1708
    Pack4x8snorm,
1709

1710
    /// Packing operator from `vec4<f32>` to `u32` (unsigned normalized).
1711
    ///
1712
    /// Convert the four components of an unsigned normalized floating point
1713
    /// vector into an unsigned integral `u8` value in `[0:255]`, then pack
1714
    /// those four values into a single `u32`. Each vector component should
1715
    /// be in `[0:1]` before packing; values outside this range are clamped.
1716
    Pack4x8unorm,
1717

1718
    /// Saturate operator.
1719
    ///
1720
    /// Clamp the value of the operand to the \[0:1\] range, component-wise for
1721
    /// vectors.
1722
    Saturate,
1723

1724
    /// Sign operator.
1725
    ///
1726
    /// Return a value representing the sign of a floating point scalar or
1727
    /// vector input:
1728
    /// - `1.` if the operand is > 0
1729
    /// - `0.` if the operand is = 0
1730
    /// - `-1.` if the operand is < 0
1731
    ///
1732
    /// Applies component-wise for vectors.
1733
    Sign,
1734

1735
    /// Sine operator.
1736
    Sin,
1737

1738
    /// Square root operator.
1739
    ///
1740
    /// Return the square root of the floating-point operand, component-wise for
1741
    /// vectors.
1742
    Sqrt,
1743

1744
    /// Tangent operator.
1745
    Tan,
1746

1747
    /// Unpacking operator from `u32` to `vec4<f32>` (signed normalized).
1748
    ///
1749
    /// Unpack the `u32` into four signed integral `i8` value in `[-128:127]`,
1750
    /// then convert each value to a signed normalized `f32` value in `[-1:1]`.
1751
    Unpack4x8snorm,
1752

1753
    /// Unpacking operator from `u32` to `vec4<f32>` (unsigned normalized).
1754
    ///
1755
    /// Unpack the `u32` into four unsigned integral `u8` value in `[0:255]`,
1756
    /// then convert each value to an unsigned normalized `f32` value in
1757
    /// `[0:1]`.
1758
    Unpack4x8unorm,
1759

1760
    /// Get the fourth component of a vector.
1761
    ///
1762
    /// This is only valid for vectors of rank 4.
1763
    W,
1764

1765
    /// Get the first component of a scalar or vector.
1766
    ///
1767
    /// For scalar, return the value itself. For vectors, return the first
1768
    /// component.
1769
    X,
1770

1771
    /// Get the second component of a vector.
1772
    Y,
1773

1774
    /// Get the third component of a vector.
1775
    ///
1776
    /// This is only valid for vectors of rank 3 or more.
1777
    Z,
1778
}
1779

1780
impl UnaryOperator {
1781
    /// Check if a unary operator is called via a functional-style call.
1782
    ///
1783
    /// Functional-style calls are in the form `op(inner)`, like `abs(x)` for
1784
    /// example, while non-functional ones are in the form `inner.op`,
1785
    /// like `v.x` for example. This check is used for formatting the WGSL
1786
    /// code emitted during evaluation of a binary operation expression.
1787
    pub fn is_functional(&self) -> bool {
34✔
1788
        !matches!(
30✔
1789
            *self,
34✔
1790
            UnaryOperator::X | UnaryOperator::Y | UnaryOperator::Z | UnaryOperator::W
1791
        )
1792
    }
1793
}
1794

1795
impl ToWgslString for UnaryOperator {
1796
    fn to_wgsl_string(&self) -> String {
34✔
1797
        match *self {
34✔
1798
            UnaryOperator::Abs => "abs".to_string(),
5✔
1799
            UnaryOperator::All => "all".to_string(),
1✔
1800
            UnaryOperator::Any => "any".to_string(),
3✔
1801
            UnaryOperator::Ceil => "ceil".to_string(),
1✔
1802
            UnaryOperator::Cos => "cos".to_string(),
1✔
1803
            UnaryOperator::Exp => "exp".to_string(),
1✔
1804
            UnaryOperator::Exp2 => "exp2".to_string(),
1✔
1805
            UnaryOperator::Floor => "floor".to_string(),
1✔
1806
            UnaryOperator::Fract => "fract".to_string(),
1✔
1807
            UnaryOperator::InvSqrt => "inverseSqrt".to_string(),
1✔
1808
            UnaryOperator::Length => "length".to_string(),
1✔
1809
            UnaryOperator::Log => "log".to_string(),
1✔
1810
            UnaryOperator::Log2 => "log2".to_string(),
1✔
1811
            UnaryOperator::Normalize => "normalize".to_string(),
2✔
1812
            UnaryOperator::Pack4x8snorm => "pack4x8snorm".to_string(),
1✔
1813
            UnaryOperator::Pack4x8unorm => "pack4x8unorm".to_string(),
1✔
1814
            UnaryOperator::Saturate => "saturate".to_string(),
1✔
1815
            UnaryOperator::Sign => "sign".to_string(),
1✔
1816
            UnaryOperator::Sin => "sin".to_string(),
1✔
1817
            UnaryOperator::Sqrt => "sqrt".to_string(),
1✔
1818
            UnaryOperator::Tan => "tan".to_string(),
1✔
1819
            UnaryOperator::Unpack4x8snorm => "unpack4x8snorm".to_string(),
1✔
1820
            UnaryOperator::Unpack4x8unorm => "unpack4x8unorm".to_string(),
1✔
1821
            UnaryOperator::W => "w".to_string(),
1✔
1822
            UnaryOperator::X => "x".to_string(),
1✔
1823
            UnaryOperator::Y => "y".to_string(),
1✔
1824
            UnaryOperator::Z => "z".to_string(),
1✔
1825
        }
1826
    }
1827
}
1828

1829
/// Binary operator.
1830
///
1831
/// Operator applied between two operands, generally denoted "left" and "right".
1832
/// The type of the operands and the result are not necessarily the same. Valid
1833
/// operand types depend on the operator itself.
1834
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
1835
pub enum BinaryOperator {
1836
    /// Addition operator.
1837
    ///
1838
    /// Returns the sum of its operands. Only valid for numeric operands.
1839
    Add,
1840

1841
    /// Cross product operator.
1842
    ///
1843
    /// Returns the cross product of the left and right operands. Only valid for
1844
    /// vector type operands of size 3. Always produce a vector result of the
1845
    /// same size.
1846
    Cross,
1847

1848
    /// Distance operator.
1849
    ///
1850
    /// Returns the distance between two floating point scalar or vectors, that
1851
    /// is `length(right - left)`.
1852
    Distance,
1853

1854
    /// Division operator.
1855
    ///
1856
    /// Returns the left operand divided by the right operand. Only valid for
1857
    /// numeric operands.
1858
    Div,
1859

1860
    /// Dot product operator.
1861
    ///
1862
    /// Returns the dot product of the left and right operands. Only valid for
1863
    /// vector type operands. Always produce a scalar floating-point result.
1864
    Dot,
1865

1866
    /// Greater-than operator.
1867
    ///
1868
    /// Returns `true` if the left operand is strictly greater than the right
1869
    /// operand. Only valid for numeric types. If the operands are vectors,
1870
    /// they must be of the same rank, and the result is a bool vector of
1871
    /// that rank.
1872
    GreaterThan,
1873

1874
    /// Greater-than-or-equal operator.
1875
    ///
1876
    /// Returns `true` if the left operand is greater than or equal to the right
1877
    /// operand. Only valid for numeric types. If the operands are vectors,
1878
    /// they must be of the same rank, and the result is a bool vector of
1879
    /// that rank.
1880
    GreaterThanOrEqual,
1881

1882
    /// Less-than operator.
1883
    ///
1884
    /// Returns `true` if the left operand is strictly less than the right
1885
    /// operand. Only valid for numeric types. If the operands are vectors,
1886
    /// they must be of the same rank, and the result is a bool vector of
1887
    /// that rank.
1888
    LessThan,
1889

1890
    /// Less-than-or-equal operator.
1891
    ///
1892
    /// Returns `true` if the left operand is less than or equal to the right
1893
    /// operand. Only valid for numeric types. If the operands are vectors,
1894
    /// they must be of the same rank, and the result is a bool vector of
1895
    /// that rank.
1896
    LessThanOrEqual,
1897

1898
    /// Maximum operator.
1899
    ///
1900
    /// Returns the maximum value of its left and right operands. Only valid for
1901
    /// numeric types. If the operands are vectors, they must be of the same
1902
    /// rank, and the result is a vector of that rank and same element
1903
    /// scalar type.
1904
    Max,
1905

1906
    /// Minimum operator.
1907
    ///
1908
    /// Returns the minimum value of its left and right operands. Only valid for
1909
    /// numeric types. If the operands are vectors, they must be of the same
1910
    /// rank, and the result is a vector of that rank and same element
1911
    /// scalar type.
1912
    Min,
1913

1914
    /// Multiply operator.
1915
    ///
1916
    /// Returns the product of its operands. Only valid for numeric operands.
1917
    Mul,
1918

1919
    /// Remainder operator.
1920
    ///
1921
    /// Returns the remainder of the division of the first operand by the
1922
    /// second. Only valid for numeric types. If the operands are vectors,
1923
    /// they must be of the same rank, and the result is a vector of that
1924
    /// rank and same element scalar type.
1925
    Remainder,
1926

1927
    /// Stepping operator.
1928
    ///
1929
    /// Returns `1.0` if the left operand is less than or equal to the right
1930
    /// operand, or `0.0` otherwise. Only valid for floating scalar or vectors
1931
    /// of the same rank, and applied component-wise for vectors.
1932
    Step,
1933

1934
    /// Subtraction operator.
1935
    ///
1936
    /// Returns the difference between its left and right operands. Only valid
1937
    /// for numeric operands.
1938
    Sub,
1939

1940
    /// Uniform random number operator.
1941
    ///
1942
    /// Returns a value generated by a fast non-cryptographically-secure
1943
    /// pseudo-random number generator (PRNG) whose statistical characteristics
1944
    /// are undefined and generally focused around speed. The random value is
1945
    /// uniformly distributed between the left and right operands, which must be
1946
    /// numeric types. If the operands are vectors, they must be of the same
1947
    /// rank, and the result is a vector of that rank and same element
1948
    /// scalar type.
1949
    UniformRand,
1950

1951
    /// Normal distribution random number operator.
1952
    ///
1953
    /// Returns a value generated by a fast non-cryptographically-secure
1954
    /// pseudo-random number generator (PRNG) whose statistical characteristics
1955
    /// are undefined and generally focused around speed. The random value is
1956
    /// normally distributed with mean given by the first operand and standard
1957
    /// deviation by the second, which must be numeric types. If the operands
1958
    /// are vectors, they must be of the same rank, and the result is a vector
1959
    /// of that rank and same element scalar type.
1960
    NormalRand,
1961

1962
    /// Constructor for 2-element vectors.
1963
    ///
1964
    /// Given two scalar elements `x` and `y`, returns the vector consisting of
1965
    /// those two elements `(x, y)`.
1966
    Vec2,
1967
}
1968

1969
impl BinaryOperator {
1970
    /// Check if a binary operator is called via a functional-style call.
1971
    ///
1972
    /// Functional-style calls are in the form `op(lhs, rhs)`, like `min(a,
1973
    /// b)` for example, while non-functional ones are in the form `lhs op rhs`,
1974
    /// like `a + b` for example. This check is used for formatting the WGSL
1975
    /// code emitted during evaluation of a binary operation expression.
1976
    pub fn is_functional(&self) -> bool {
38✔
1977
        match *self {
38✔
1978
            BinaryOperator::Add
1979
            | BinaryOperator::Div
1980
            | BinaryOperator::GreaterThan
1981
            | BinaryOperator::GreaterThanOrEqual
1982
            | BinaryOperator::LessThan
1983
            | BinaryOperator::LessThanOrEqual
1984
            | BinaryOperator::Mul
1985
            | BinaryOperator::Remainder
1986
            | BinaryOperator::Sub => false,
27✔
1987
            BinaryOperator::Cross
1988
            | BinaryOperator::Distance
1989
            | BinaryOperator::Dot
1990
            | BinaryOperator::Max
1991
            | BinaryOperator::Min
1992
            | BinaryOperator::Step
1993
            | BinaryOperator::UniformRand
1994
            | BinaryOperator::NormalRand
1995
            | BinaryOperator::Vec2 => true,
11✔
1996
        }
1997
    }
1998

1999
    /// Check if a binary operator needs a type suffix.
2000
    ///
2001
    /// This is currently just for `rand_uniform`
2002
    /// (`BinaryOperator::UniformRand`) and `rand_normal`
2003
    /// (`BinaryOperator::NormalRand`), which are functions we define ourselves.
2004
    /// WGSL doesn't support user-defined function overloading, so we need a
2005
    /// suffix to disambiguate the types.
2006
    pub fn needs_type_suffix(&self) -> bool {
11✔
2007
        matches!(
11✔
2008
            *self,
11✔
2009
            BinaryOperator::UniformRand | BinaryOperator::NormalRand
2010
        )
2011
    }
2012
}
2013

2014
impl ToWgslString for BinaryOperator {
2015
    fn to_wgsl_string(&self) -> String {
38✔
2016
        match *self {
38✔
2017
            BinaryOperator::Add => "+".to_string(),
5✔
2018
            BinaryOperator::Cross => "cross".to_string(),
1✔
2019
            BinaryOperator::Distance => "distance".to_string(),
1✔
2020
            BinaryOperator::Div => "/".to_string(),
2✔
2021
            BinaryOperator::Dot => "dot".to_string(),
1✔
2022
            BinaryOperator::GreaterThan => ">".to_string(),
3✔
2023
            BinaryOperator::GreaterThanOrEqual => ">=".to_string(),
1✔
2024
            BinaryOperator::LessThan => "<".to_string(),
1✔
2025
            BinaryOperator::LessThanOrEqual => "<=".to_string(),
1✔
2026
            BinaryOperator::Max => "max".to_string(),
5✔
2027
            BinaryOperator::Min => "min".to_string(),
2✔
2028
            BinaryOperator::Mul => "*".to_string(),
6✔
2029
            BinaryOperator::Remainder => "%".to_string(),
1✔
2030
            BinaryOperator::Step => "step".to_string(),
1✔
2031
            BinaryOperator::Sub => "-".to_string(),
7✔
2032
            BinaryOperator::UniformRand => "rand_uniform".to_string(),
×
NEW
2033
            BinaryOperator::NormalRand => "rand_normal".to_string(),
×
UNCOV
2034
            BinaryOperator::Vec2 => "vec2".to_string(),
×
2035
        }
2036
    }
2037
}
2038

2039
/// Ternary operator.
2040
///
2041
/// Operator applied between three operands. The type of the operands and the
2042
/// result are not necessarily the same. Valid operand types depend on the
2043
/// operator itself.
2044
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Reflect, Serialize, Deserialize)]
2045
pub enum TernaryOperator {
2046
    /// Linear blend ("mix") operator.
2047
    ///
2048
    /// Returns the linear blend between the first and second argument, based on
2049
    /// the fraction of the third argument. If the operands are vectors, they
2050
    /// must be of the same rank, and the result is a vector of that rank
2051
    /// and same element scalar type.
2052
    ///
2053
    /// The linear blend of `x` and `y` with fraction `t` is equivalent to `x *
2054
    /// (1 - t) + y * t`.
2055
    Mix,
2056

2057
    /// Smooth stepping operator.
2058
    ///
2059
    /// Returns the smooth Hermitian interpolation between the first and second
2060
    /// argument, calculated at the third argument. If the operands are vectors,
2061
    /// they must be of the same rank, and the result is a vector of that
2062
    /// rank and same element scalar type.
2063
    ///
2064
    /// The smooth stepping of `low` and `high` at position `x` is equivalent to
2065
    /// `t * t * (3. - 2. * t)` where `t = clamp((x - low) / (high - low))`
2066
    /// represents the fractional position of `x` between `low` and `high`.
2067
    ///
2068
    /// The result is always a floating point scalar in \[0:1\].
2069
    SmoothStep,
2070

2071
    /// Constructor for 3-element vectors.
2072
    ///
2073
    /// Given three scalar elements `x`, `y`, and `z`, returns the vector
2074
    /// consisting of those three elements `(x, y, z)`.
2075
    Vec3,
2076
}
2077

2078
impl ToWgslString for TernaryOperator {
2079
    fn to_wgsl_string(&self) -> String {
3✔
2080
        match *self {
3✔
2081
            TernaryOperator::Mix => "mix".to_string(),
2✔
2082
            TernaryOperator::SmoothStep => "smoothstep".to_string(),
1✔
2083
            TernaryOperator::Vec3 => "vec3".to_string(),
×
2084
        }
2085
    }
2086
}
2087

2088
/// Expression writer.
2089
///
2090
/// Utility to write expressions with a simple functional syntax. Expressions
2091
/// created with the writer are gatherned into a [`Module`] which can be
2092
/// transfered once [`finish()`]ed to initialize an [`EffectAsset`].
2093
///
2094
/// Because an [`EffectAsset`] contains a single [`Module`], you generally want
2095
/// to keep using the same [`ExprWriter`] to write all the expressions used by
2096
/// all the [`Modifer`]s assigned to a given [`EffectAsset`], and only then once
2097
/// done call [`finish()`] to recover the [`ExprWriter`]'s underlying [`Module`]
2098
/// to assign it to the [`EffectAsset`].
2099
///
2100
/// # Example
2101
///
2102
/// ```
2103
/// # use bevy_hanabi::*;
2104
/// # use bevy::prelude::*;
2105
/// // Create a writer
2106
/// let w = ExprWriter::new();
2107
///
2108
/// // Create a new expression: max(5. + particle.position, properties.my_prop)
2109
/// let prop = w.add_property("my_property", Vec3::ONE.into());
2110
/// let expr = (w.lit(5.) + w.attr(Attribute::POSITION)).max(w.prop(prop));
2111
///
2112
/// // Finalize the expression and write it down into the `Module` as an `Expr`
2113
/// let expr: ExprHandle = expr.expr();
2114
///
2115
/// // Create a modifier and assign the expression to one of its input(s)
2116
/// let init_modifier = SetAttributeModifier::new(Attribute::LIFETIME, expr);
2117
///
2118
/// // Create an EffectAsset with the modifier and the Module from the writer
2119
/// let effect =
2120
///     EffectAsset::new(vec![1024], Spawner::rate(32_f32.into()), w.finish()).init(init_modifier);
2121
/// ```
2122
///
2123
/// [`finish()`]: ExprWriter::finish
2124
/// [`EffectAsset`]: crate::EffectAsset
2125
/// [`Modifer`]: crate::Modifier
2126
#[derive(Debug, Default, Clone)]
2127
pub struct ExprWriter {
2128
    module: Rc<RefCell<Module>>,
2129
}
2130

2131
#[allow(dead_code)]
2132
impl ExprWriter {
2133
    /// Create a new writer.
2134
    ///
2135
    /// The writer owns a new [`Module`] internally, and write all expressions
2136
    /// to it. The module can be released to the user with [`finish()`] once
2137
    /// done using the writer.
2138
    ///
2139
    /// [`finish()`]: ExprWriter::finish
2140
    pub fn new() -> Self {
3✔
2141
        Self {
2142
            module: Rc::new(RefCell::new(Module::default())),
3✔
2143
        }
2144
    }
2145

2146
    /// Create a new writer from an existing module.
2147
    ///
2148
    /// This is an advanced use entry point to write expressions into an
2149
    /// existing [`Module`]. In general, users should prefer using
2150
    /// [`ExprWriter::new()`] to create a new [`Module`], and keep using the
2151
    /// same [`ExprWriter`] to write all expressions of the same
2152
    /// [`EffectAsset`].
2153
    ///
2154
    /// [`EffectAsset`]: crate::EffectAsset
2155
    pub fn from_module(module: Rc<RefCell<Module>>) -> Self {
×
2156
        Self { module }
2157
    }
2158

2159
    /// Add a new property.
2160
    ///
2161
    /// See [`Property`] for more details on what effect properties are.
2162
    ///
2163
    /// # Panics
2164
    ///
2165
    /// Panics if a property with the same name already exists.
2166
    pub fn add_property(&self, name: impl Into<String>, default_value: Value) -> PropertyHandle {
1✔
2167
        self.module.borrow_mut().add_property(name, default_value)
1✔
2168
    }
2169

2170
    /// Push a new expression into the writer.
2171
    pub fn push(&self, expr: impl Into<Expr>) -> WriterExpr {
13✔
2172
        let expr = {
13✔
2173
            let mut m = self.module.borrow_mut();
13✔
2174
            m.push(expr.into())
13✔
2175
        };
2176
        WriterExpr {
2177
            expr,
2178
            module: Rc::clone(&self.module),
13✔
2179
        }
2180
    }
2181

2182
    /// Create a new writer expression from a literal constant.
2183
    ///
2184
    /// # Example
2185
    ///
2186
    /// ```
2187
    /// # use bevy_hanabi::*;
2188
    /// let mut w = ExprWriter::new();
2189
    /// let x = w.lit(-3.5); // x = -3.5;
2190
    /// ```
2191
    pub fn lit(&self, value: impl Into<Value>) -> WriterExpr {
11✔
2192
        self.push(Expr::Literal(LiteralExpr {
11✔
2193
            value: value.into(),
11✔
2194
        }))
2195
    }
2196

2197
    /// Create a new writer expression from an attribute.
2198
    ///
2199
    /// # Example
2200
    ///
2201
    /// ```
2202
    /// # use bevy_hanabi::*;
2203
    /// let mut w = ExprWriter::new();
2204
    /// let x = w.attr(Attribute::POSITION); // x = particle.position;
2205
    /// ```
2206
    pub fn attr(&self, attr: Attribute) -> WriterExpr {
1✔
2207
        self.push(Expr::Attribute(AttributeExpr::new(attr)))
1✔
2208
    }
2209

2210
    /// Create a new writer expression from a property.
2211
    ///
2212
    /// # Example
2213
    ///
2214
    /// ```
2215
    /// # use bevy_hanabi::*;
2216
    /// let mut w = ExprWriter::new();
2217
    /// let prop = w.add_property("my_prop", 3.0.into());
2218
    /// let x = w.prop(prop); // x = properties.my_prop;
2219
    /// ```
2220
    pub fn prop(&self, handle: PropertyHandle) -> WriterExpr {
1✔
2221
        self.push(Expr::Property(PropertyExpr::new(handle)))
1✔
2222
    }
2223

2224
    /// Create a new writer expression representing the current simulation time.
2225
    ///
2226
    /// # Example
2227
    ///
2228
    /// ```
2229
    /// # use bevy_hanabi::*;
2230
    /// let mut w = ExprWriter::new();
2231
    /// let x = w.time(); // x = sim_params.time;
2232
    /// ```
2233
    pub fn time(&self) -> WriterExpr {
×
2234
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Time)))
×
2235
    }
2236

2237
    /// Create a new writer expression representing the simulation delta time
2238
    /// since last frame.
2239
    ///
2240
    /// # Example
2241
    ///
2242
    /// ```
2243
    /// # use bevy_hanabi::*;
2244
    /// let mut w = ExprWriter::new();
2245
    /// let x = w.delta_time(); // x = sim_params.delta_time;
2246
    /// ```
2247
    pub fn delta_time(&self) -> WriterExpr {
×
2248
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::DeltaTime)))
×
2249
    }
2250

2251
    /// Create a new writer expression representing a random value of the given
2252
    /// type.
2253
    ///
2254
    /// The type can be any scalar or vector type. Matrix types are not
2255
    /// supported. The random values generated are uniformly distributed in
2256
    /// `[0:1]`. For vectors, each component is sampled separately.
2257
    ///
2258
    /// # Panics
2259
    ///
2260
    /// Panics in the same cases as [`BuiltInExpr::new()`] does.
2261
    ///
2262
    /// # Example
2263
    ///
2264
    /// ```
2265
    /// # use bevy_hanabi::*;
2266
    /// let mut w = ExprWriter::new();
2267
    /// let x = w.rand(VectorType::VEC3F); // x = frand3();
2268
    /// ```
2269
    pub fn rand(&self, value_type: impl Into<ValueType>) -> WriterExpr {
×
2270
        self.push(Expr::BuiltIn(BuiltInExpr::new(BuiltInOperator::Rand(
×
2271
            value_type.into(),
×
2272
        ))))
2273
    }
2274

2275
    /// Create a new writer expression representing the alpha cutoff value used
2276
    /// for alpha masking.
2277
    ///
2278
    /// This expression is only valid when used in the context of the fragment
2279
    /// shader, in the render context.
2280
    ///
2281
    /// # Example
2282
    ///
2283
    /// ```
2284
    /// # use bevy_hanabi::*;
2285
    /// let mut w = ExprWriter::new();
2286
    /// let x = w.alpha_cutoff(); // x = alpha_cutoff;
2287
    /// ```
2288
    pub fn alpha_cutoff(&self) -> WriterExpr {
×
2289
        self.push(Expr::BuiltIn(BuiltInExpr::new(
×
2290
            BuiltInOperator::AlphaCutoff,
×
2291
        )))
2292
    }
2293

2294
    /// Finish using the writer, and recover the [`Module`] where all [`Expr`]
2295
    /// were written by the writer.
2296
    ///
2297
    /// This module is typically passed to [`EffectAsset::new()`] before adding
2298
    /// to that effect the modifiers which use the expressions created by this
2299
    /// writer.
2300
    ///
2301
    /// # Example
2302
    ///
2303
    /// ```
2304
    /// # use bevy_hanabi::*;
2305
    /// # let spawner = Spawner::default();
2306
    /// let mut w = ExprWriter::new();
2307
    /// // [...]
2308
    /// let module = w.finish();
2309
    /// let asset = EffectAsset::new(vec![256], spawner, module);
2310
    /// ```
2311
    ///
2312
    /// [`EffectAsset::new()`]: crate::EffectAsset::new()
2313
    pub fn finish(self) -> Module {
3✔
2314
        self.module.take()
3✔
2315
    }
2316
}
2317

2318
/// Intermediate expression from an [`ExprWriter`].
2319
///
2320
/// A writer expression [`WriterExpr`] is equivalent to an [`ExprHandle`], but
2321
/// retains a reference to the underlying [`Module`] and therefore can easily be
2322
/// chained with other [`WriterExpr`] via a concise syntax, at the expense of
2323
/// being more heavyweight and locking the underlying [`Module`] under a
2324
/// ref-counted interior mutability (`Rc<RefCell<Module>>`). [`ExprHandle`] by
2325
/// opposition is a very lightweight type, similar to a simple index. And like
2326
/// an array index, [`ExprHandle`] doesn't explicitly reference its associated
2327
/// storage ([`Module`]) which needs to be remembered by the user explicitly.
2328
///
2329
/// In addition, [`WriterExpr`] implements several numerical operators like the
2330
/// [`std::ops::Add`] trait, making it simpler to combine it with another
2331
/// [`WriterExpr`].
2332
///
2333
/// ```
2334
/// # use bevy_hanabi::*;
2335
/// let mut w = ExprWriter::new();
2336
/// let x = w.lit(-3.5);
2337
/// let y = w.lit(78.);
2338
/// let z = x + y; // == 74.5
2339
/// ```
2340
///
2341
/// In general the [`WriterExpr`] type is not used directly, but inferred from
2342
/// calling [`ExprWriter`] methods and combining [`WriterExpr`] together.
2343
///
2344
/// ```
2345
/// # use bevy_hanabi::*;
2346
/// let mut w = ExprWriter::new();
2347
/// let my_prop = w.add_property("my_prop", 3.0.into());
2348
///
2349
/// // x = max(-3.5 + 1., properties.my_prop) * 0.5 - particle.position;
2350
/// let x = (w.lit(-3.5) + w.lit(1.))
2351
///     .max(w.prop(my_prop))
2352
///     .mul(w.lit(0.5))
2353
///     .sub(w.attr(Attribute::POSITION));
2354
///
2355
/// let handle: ExprHandle = x.expr();
2356
/// ```
2357
#[derive(Debug, Clone)]
2358
pub struct WriterExpr {
2359
    expr: ExprHandle,
2360
    module: Rc<RefCell<Module>>,
2361
}
2362

2363
impl WriterExpr {
2364
    fn unary_op(self, op: UnaryOperator) -> Self {
1✔
2365
        let expr = self.module.borrow_mut().push(Expr::Unary {
1✔
2366
            op,
1✔
2367
            expr: self.expr,
1✔
2368
        });
2369
        WriterExpr {
2370
            expr,
2371
            module: self.module,
1✔
2372
        }
2373
    }
2374

2375
    /// Take the absolute value of the current expression.
2376
    ///
2377
    /// This is a unary operator, which applies component-wise to vector and
2378
    /// matrix operand expressions.
2379
    ///
2380
    /// # Example
2381
    ///
2382
    /// ```
2383
    /// # use bevy_hanabi::*;
2384
    /// # let mut w = ExprWriter::new();
2385
    /// // A literal expression `x = -3.5;`.
2386
    /// let x = w.lit(-3.5);
2387
    ///
2388
    /// // The absolute value `y = abs(x);`.
2389
    /// let y = x.abs(); // == 3.5
2390
    /// ```
2391
    #[inline]
2392
    pub fn abs(self) -> Self {
1✔
2393
        self.unary_op(UnaryOperator::Abs)
1✔
2394
    }
2395

2396
    /// Apply the logical operator "all" to the current bool vector expression.
2397
    ///
2398
    /// This is a unary operator, which applies to vector operand expressions to
2399
    /// produce a scalar boolean.
2400
    ///
2401
    /// # Example
2402
    ///
2403
    /// ```
2404
    /// # use bevy_hanabi::*;
2405
    /// # use bevy::math::BVec3;
2406
    /// # let mut w = ExprWriter::new();
2407
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2408
    /// let x = w.lit(BVec3::new(true, false, true));
2409
    ///
2410
    /// // Check if all components are true `y = all(x);`.
2411
    /// let y = x.all(); // == false
2412
    /// ```
2413
    #[inline]
2414
    pub fn all(self) -> Self {
×
2415
        self.unary_op(UnaryOperator::All)
×
2416
    }
2417

2418
    /// Apply the logical operator "any" to the current bool vector expression.
2419
    ///
2420
    /// This is a unary operator, which applies to vector operand expressions to
2421
    /// produce a scalar boolean.
2422
    ///
2423
    /// # Example
2424
    ///
2425
    /// ```
2426
    /// # use bevy_hanabi::*;
2427
    /// # use bevy::math::BVec3;
2428
    /// # let mut w = ExprWriter::new();
2429
    /// // A literal expression `x = vec3<bool>(true, false, true);`.
2430
    /// let x = w.lit(BVec3::new(true, false, true));
2431
    ///
2432
    /// // Check if any components is true `y = any(x);`.
2433
    /// let y = x.any(); // == true
2434
    /// ```
2435
    #[inline]
2436
    pub fn any(self) -> Self {
×
2437
        self.unary_op(UnaryOperator::Any)
×
2438
    }
2439

2440
    /// Apply the "ceil" operator to the current float scalar or vector
2441
    /// expression.
2442
    ///
2443
    /// This is a unary operator, which applies to float scalar or vector
2444
    /// operand expressions to produce a float scalar or vector. It applies
2445
    /// component-wise to vector operand expressions.
2446
    ///
2447
    /// # Example
2448
    ///
2449
    /// ```
2450
    /// # use bevy_hanabi::*;
2451
    /// # use bevy::math::Vec3;
2452
    /// # let mut w = ExprWriter::new();
2453
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2454
    /// let x = w.lit(Vec3::ONE);
2455
    ///
2456
    /// // Ceil: `y = ceil(x);`
2457
    /// let y = x.ceil();
2458
    /// ```
2459
    #[inline]
2460
    pub fn ceil(self) -> Self {
×
2461
        self.unary_op(UnaryOperator::Ceil)
×
2462
    }
2463

2464
    /// Apply the "cos" operator to the current float scalar or vector
2465
    /// expression.
2466
    ///
2467
    /// This is a unary operator, which applies to float scalar or vector
2468
    /// operand expressions to produce a float scalar or vector. It applies
2469
    /// component-wise to vector operand expressions.
2470
    ///
2471
    /// # Example
2472
    ///
2473
    /// ```
2474
    /// # use bevy_hanabi::*;
2475
    /// # use bevy::math::Vec3;
2476
    /// # let mut w = ExprWriter::new();
2477
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2478
    /// let x = w.lit(Vec3::ONE);
2479
    ///
2480
    /// // Cos: `y = cos(x);`
2481
    /// let y = x.cos();
2482
    /// ```
2483
    #[inline]
2484
    pub fn cos(self) -> Self {
×
2485
        self.unary_op(UnaryOperator::Cos)
×
2486
    }
2487

2488
    /// Apply the "exp" operator to the current float scalar or vector
2489
    /// expression.
2490
    ///
2491
    /// This is a unary operator, which applies to float scalar or vector
2492
    /// operand expressions to produce a float scalar or vector. It applies
2493
    /// component-wise to vector operand expressions.
2494
    ///
2495
    /// # Example
2496
    ///
2497
    /// ```
2498
    /// # use bevy_hanabi::*;
2499
    /// # use bevy::math::Vec3;
2500
    /// # let mut w = ExprWriter::new();
2501
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2502
    /// let x = w.lit(Vec3::ONE);
2503
    ///
2504
    /// // Exp: `y = exp(x);`
2505
    /// let y = x.exp();
2506
    /// ```
2507
    #[inline]
2508
    pub fn exp(self) -> Self {
×
2509
        self.unary_op(UnaryOperator::Exp)
×
2510
    }
2511

2512
    /// Apply the "exp2" operator to the current float scalar or vector
2513
    /// expression.
2514
    ///
2515
    /// This is a unary operator, which applies to float scalar or vector
2516
    /// operand expressions to produce a float scalar or vector. It applies
2517
    /// component-wise to vector operand expressions.
2518
    ///
2519
    /// # Example
2520
    ///
2521
    /// ```
2522
    /// # use bevy_hanabi::*;
2523
    /// # use bevy::math::Vec3;
2524
    /// # let mut w = ExprWriter::new();
2525
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2526
    /// let x = w.lit(Vec3::ONE);
2527
    ///
2528
    /// // Exp2: `y = exp2(x);`
2529
    /// let y = x.exp2();
2530
    /// ```
2531
    #[inline]
2532
    pub fn exp2(self) -> Self {
×
2533
        self.unary_op(UnaryOperator::Exp2)
×
2534
    }
2535

2536
    /// Apply the "floor" operator to the current float scalar or vector
2537
    /// expression.
2538
    ///
2539
    /// This is a unary operator, which applies to float scalar or vector
2540
    /// operand expressions to produce a float scalar or vector. It applies
2541
    /// component-wise to vector operand expressions.
2542
    ///
2543
    /// # Example
2544
    ///
2545
    /// ```
2546
    /// # use bevy_hanabi::*;
2547
    /// # use bevy::math::Vec3;
2548
    /// # let mut w = ExprWriter::new();
2549
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2550
    /// let x = w.lit(Vec3::ONE);
2551
    ///
2552
    /// // Floor: `y = floor(x);`
2553
    /// let y = x.floor();
2554
    /// ```
2555
    #[inline]
2556
    pub fn floor(self) -> Self {
×
2557
        self.unary_op(UnaryOperator::Floor)
×
2558
    }
2559

2560
    /// Apply the "fract" operator to the current float scalar or vector
2561
    /// expression.
2562
    ///
2563
    /// This is a unary operator, which applies to float scalar or vector
2564
    /// operand expressions to produce a float scalar or vector. It applies
2565
    /// component-wise to vector operand expressions.
2566
    ///
2567
    /// # Example
2568
    ///
2569
    /// ```
2570
    /// # use bevy_hanabi::*;
2571
    /// # use bevy::math::Vec3;
2572
    /// # let mut w = ExprWriter::new();
2573
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2574
    /// let x = w.lit(Vec3::ONE);
2575
    ///
2576
    /// // Fract: `y = fract(x);`
2577
    /// let y = x.fract();
2578
    /// ```
2579
    #[inline]
2580
    pub fn fract(self) -> Self {
×
2581
        self.unary_op(UnaryOperator::Fract)
×
2582
    }
2583

2584
    /// Apply the "inverseSqrt" (inverse square root) operator to the current
2585
    /// float scalar or vector expression.
2586
    ///
2587
    /// This is a unary operator, which applies to float scalar or vector
2588
    /// operand expressions to produce a float scalar or vector. It applies
2589
    /// component-wise to vector operand expressions.
2590
    ///
2591
    /// # Example
2592
    ///
2593
    /// ```
2594
    /// # use bevy_hanabi::*;
2595
    /// # use bevy::math::Vec3;
2596
    /// # let mut w = ExprWriter::new();
2597
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2598
    /// let x = w.lit(Vec3::ONE);
2599
    ///
2600
    /// // Inverse square root: `y = inverseSqrt(x) = 1.0 / sqrt(x);`
2601
    /// let y = x.inverse_sqrt();
2602
    /// ```
2603
    #[inline]
2604
    pub fn inverse_sqrt(self) -> Self {
×
2605
        self.unary_op(UnaryOperator::InvSqrt)
×
2606
    }
2607

2608
    /// Apply the "length" operator to the current float scalar or vector
2609
    /// expression.
2610
    ///
2611
    /// This is a unary operator, which applies to float scalar or vector
2612
    /// operand expressions to produce a float scalar or vector. It applies
2613
    /// component-wise to vector operand expressions.
2614
    ///
2615
    /// # Example
2616
    ///
2617
    /// ```
2618
    /// # use bevy_hanabi::*;
2619
    /// # use bevy::math::Vec3;
2620
    /// # let mut w = ExprWriter::new();
2621
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2622
    /// let x = w.lit(Vec3::ONE);
2623
    ///
2624
    /// // Length: `y = length(x);`
2625
    /// let y = x.length();
2626
    /// ```
2627
    #[inline]
2628
    pub fn length(self) -> Self {
×
2629
        self.unary_op(UnaryOperator::Length)
×
2630
    }
2631

2632
    /// Apply the "log" operator to the current float scalar or vector
2633
    /// expression.
2634
    ///
2635
    /// This is a unary operator, which applies to float scalar or vector
2636
    /// operand expressions to produce a float scalar or vector. It applies
2637
    /// component-wise to vector operand expressions.
2638
    ///
2639
    /// # Example
2640
    ///
2641
    /// ```
2642
    /// # use bevy_hanabi::*;
2643
    /// # use bevy::math::Vec3;
2644
    /// # let mut w = ExprWriter::new();
2645
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2646
    /// let x = w.lit(Vec3::ONE);
2647
    ///
2648
    /// // Log: `y = log(x);`
2649
    /// let y = x.log();
2650
    /// ```
2651
    #[inline]
2652
    pub fn log(self) -> Self {
×
2653
        self.unary_op(UnaryOperator::Log)
×
2654
    }
2655

2656
    /// Apply the "log2" operator to the current float scalar or vector
2657
    /// expression.
2658
    ///
2659
    /// This is a unary operator, which applies to float scalar or vector
2660
    /// operand expressions to produce a float scalar or vector. It applies
2661
    /// component-wise to vector operand expressions.
2662
    ///
2663
    /// # Example
2664
    ///
2665
    /// ```
2666
    /// # use bevy_hanabi::*;
2667
    /// # use bevy::math::Vec3;
2668
    /// # let mut w = ExprWriter::new();
2669
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2670
    /// let x = w.lit(Vec3::ONE);
2671
    ///
2672
    /// // Log2: `y = log2(x);`
2673
    /// let y = x.log2();
2674
    /// ```
2675
    #[inline]
2676
    pub fn log2(self) -> Self {
×
2677
        self.unary_op(UnaryOperator::Log2)
×
2678
    }
2679

2680
    /// Apply the "normalize" operator to the current float vector expression.
2681
    ///
2682
    /// This is a unary operator, which applies to float vector operand
2683
    /// expressions to produce another float vector with unit length
2684
    /// (normalized).
2685
    ///
2686
    /// # Example
2687
    ///
2688
    /// ```
2689
    /// # use bevy_hanabi::*;
2690
    /// # use bevy::math::Vec3;
2691
    /// # let mut w = ExprWriter::new();
2692
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2693
    /// let x = w.lit(Vec3::ONE);
2694
    ///
2695
    /// // Normalize: `y = normalize(x);`
2696
    /// let y = x.normalized();
2697
    /// ```
2698
    #[inline]
2699
    pub fn normalized(self) -> Self {
×
2700
        self.unary_op(UnaryOperator::Normalize)
×
2701
    }
2702

2703
    /// Apply the "pack4x8snorm" operator to the current 4-component float
2704
    /// vector expression.
2705
    ///
2706
    /// This is a unary operator, which applies to 4-component float vector
2707
    /// operand expressions to produce a single `u32` scalar expression.
2708
    ///
2709
    /// # Example
2710
    ///
2711
    /// ```
2712
    /// # use bevy_hanabi::*;
2713
    /// # use bevy::math::Vec4;
2714
    /// # let mut w = ExprWriter::new();
2715
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
2716
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
2717
    ///
2718
    /// // Pack: `y = pack4x8snorm(x);`
2719
    /// let y = x.pack4x8snorm(); // 0x7F007FFFu32
2720
    /// ```
2721
    #[inline]
2722
    pub fn pack4x8snorm(self) -> Self {
×
2723
        self.unary_op(UnaryOperator::Pack4x8snorm)
×
2724
    }
2725

2726
    /// Apply the "pack4x8unorm" operator to the current 4-component float
2727
    /// vector expression.
2728
    ///
2729
    /// This is a unary operator, which applies to 4-component float vector
2730
    /// operand expressions to produce a single `u32` scalar expression.
2731
    ///
2732
    /// # Example
2733
    ///
2734
    /// ```
2735
    /// # use bevy_hanabi::*;
2736
    /// # use bevy::math::Vec4;
2737
    /// # let mut w = ExprWriter::new();
2738
    /// // A literal expression `x = vec4<f32>(-1., 1., 0., 7.2);`.
2739
    /// let x = w.lit(Vec4::new(-1., 1., 0., 7.2));
2740
    ///
2741
    /// // Pack: `y = pack4x8unorm(x);`
2742
    /// let y = x.pack4x8unorm(); // 0xFF00FF00u32
2743
    /// ```
2744
    #[inline]
2745
    pub fn pack4x8unorm(self) -> Self {
×
2746
        self.unary_op(UnaryOperator::Pack4x8unorm)
×
2747
    }
2748

2749
    /// Apply the "sign" operator to the current float scalar or vector
2750
    /// expression.
2751
    ///
2752
    /// This is a unary operator, which applies to float scalar or vector
2753
    /// operand expressions to produce a float scalar or vector. It applies
2754
    /// component-wise to vector operand expressions.
2755
    ///
2756
    /// # Example
2757
    ///
2758
    /// ```
2759
    /// # use bevy_hanabi::*;
2760
    /// # use bevy::math::Vec3;
2761
    /// # let mut w = ExprWriter::new();
2762
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2763
    /// let x = w.lit(Vec3::ONE);
2764
    ///
2765
    /// // Sign: `y = sign(x);`
2766
    /// let y = x.sign();
2767
    /// ```
2768
    #[inline]
2769
    pub fn sign(self) -> Self {
×
2770
        self.unary_op(UnaryOperator::Sign)
×
2771
    }
2772

2773
    /// Apply the "sin" operator to the current float scalar or vector
2774
    /// expression.
2775
    ///
2776
    /// This is a unary operator, which applies to float scalar or vector
2777
    /// operand expressions to produce a float scalar or vector. It applies
2778
    /// component-wise to vector operand expressions.
2779
    ///
2780
    /// # Example
2781
    ///
2782
    /// ```
2783
    /// # use bevy_hanabi::*;
2784
    /// # use bevy::math::Vec3;
2785
    /// # let mut w = ExprWriter::new();
2786
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2787
    /// let x = w.lit(Vec3::ONE);
2788
    ///
2789
    /// // Sin: `y = sin(x);`
2790
    /// let y = x.sin();
2791
    /// ```
2792
    #[inline]
2793
    pub fn sin(self) -> Self {
×
2794
        self.unary_op(UnaryOperator::Sin)
×
2795
    }
2796

2797
    /// Apply the "sqrt" (square root) operator to the current float scalar or
2798
    /// vector expression.
2799
    ///
2800
    /// This is a unary operator, which applies to float scalar or vector
2801
    /// operand expressions to produce a float scalar or vector. It applies
2802
    /// component-wise to vector operand expressions.
2803
    ///
2804
    /// # Example
2805
    ///
2806
    /// ```
2807
    /// # use bevy_hanabi::*;
2808
    /// # use bevy::math::Vec3;
2809
    /// # let mut w = ExprWriter::new();
2810
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2811
    /// let x = w.lit(Vec3::ONE);
2812
    ///
2813
    /// // Square root: `y = sqrt(x);`
2814
    /// let y = x.sqrt();
2815
    /// ```
2816
    #[inline]
2817
    pub fn sqrt(self) -> Self {
×
2818
        self.unary_op(UnaryOperator::Sqrt)
×
2819
    }
2820

2821
    /// Apply the "tan" operator to the current float scalar or vector
2822
    /// expression.
2823
    ///
2824
    /// This is a unary operator, which applies to float scalar or vector
2825
    /// operand expressions to produce a float scalar or vector. It applies
2826
    /// component-wise to vector operand expressions.
2827
    ///
2828
    /// # Example
2829
    ///
2830
    /// ```
2831
    /// # use bevy_hanabi::*;
2832
    /// # use bevy::math::Vec3;
2833
    /// # let mut w = ExprWriter::new();
2834
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2835
    /// let x = w.lit(Vec3::ONE);
2836
    ///
2837
    /// // Tan: `y = tan(x);`
2838
    /// let y = x.tan();
2839
    /// ```
2840
    #[inline]
2841
    pub fn tan(self) -> Self {
×
2842
        self.unary_op(UnaryOperator::Tan)
×
2843
    }
2844

2845
    /// Apply the "unpack4x8snorm" operator to the current `u32` scalar
2846
    /// expression.
2847
    ///
2848
    /// This is a unary operator, which applies to `u32` scalar operand
2849
    /// expressions to produce a 4-component floating point vector of signed
2850
    /// normalized components in `[-1:1]`.
2851
    ///
2852
    /// # Example
2853
    ///
2854
    /// ```
2855
    /// # use bevy_hanabi::*;
2856
    /// # use bevy::math::Vec3;
2857
    /// # let mut w = ExprWriter::new();
2858
    /// // A literal expression `y = 0x7F007FFFu32;`.
2859
    /// let y = w.lit(0x7F007FFFu32);
2860
    ///
2861
    /// // Unpack: `x = unpack4x8snorm(y);`
2862
    /// let x = y.unpack4x8snorm(); // vec4<f32>(-1., 1., 0., 7.2)
2863
    /// ```
2864
    #[inline]
2865
    pub fn unpack4x8snorm(self) -> Self {
×
2866
        self.unary_op(UnaryOperator::Unpack4x8snorm)
×
2867
    }
2868

2869
    /// Apply the "unpack4x8unorm" operator to the current `u32` scalar
2870
    /// expression.
2871
    ///
2872
    /// This is a unary operator, which applies to `u32` scalar operand
2873
    /// expressions to produce a 4-component floating point vector of unsigned
2874
    /// normalized components in `[0:1]`.
2875
    ///
2876
    /// # Example
2877
    ///
2878
    /// ```
2879
    /// # use bevy_hanabi::*;
2880
    /// # use bevy::math::Vec3;
2881
    /// # let mut w = ExprWriter::new();
2882
    /// // A literal expression `y = 0xFF00FF00u32;`.
2883
    /// let y = w.lit(0xFF00FF00u32);
2884
    ///
2885
    /// // Unpack: `x = unpack4x8unorm(y);`
2886
    /// let x = y.unpack4x8unorm(); // vec4<f32>(-1., 1., 0., 7.2)
2887
    /// ```
2888
    #[inline]
2889
    pub fn unpack4x8unorm(self) -> Self {
×
2890
        self.unary_op(UnaryOperator::Unpack4x8unorm)
×
2891
    }
2892

2893
    /// Apply the "saturate" operator to the current float scalar or vector
2894
    /// expression.
2895
    ///
2896
    /// This is a unary operator, which applies to float scalar or vector
2897
    /// operand expressions to produce a float scalar or vector. It applies
2898
    /// component-wise to vector operand expressions.
2899
    ///
2900
    /// # Example
2901
    ///
2902
    /// ```
2903
    /// # use bevy_hanabi::*;
2904
    /// # use bevy::math::Vec3;
2905
    /// # let mut w = ExprWriter::new();
2906
    /// // A literal expression `x = vec3<f32>(1., 1., 1.);`.
2907
    /// let x = w.lit(Vec3::ONE);
2908
    ///
2909
    /// // Saturate: `y = saturate(x);`
2910
    /// let y = x.saturate();
2911
    /// ```
2912
    #[inline]
2913
    pub fn saturate(self) -> Self {
×
2914
        self.unary_op(UnaryOperator::Saturate)
×
2915
    }
2916

2917
    /// Get the first component of a scalar or vector.
2918
    ///
2919
    /// # Example
2920
    ///
2921
    /// ```
2922
    /// # use bevy_hanabi::*;
2923
    /// # use bevy::math::Vec3;
2924
    /// # let mut w = ExprWriter::new();
2925
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
2926
    /// let v = w.lit(Vec3::ONE);
2927
    ///
2928
    /// // f = v.x;`
2929
    /// let f = v.x();
2930
    /// ```
2931
    #[inline]
2932
    pub fn x(self) -> Self {
×
2933
        self.unary_op(UnaryOperator::X)
×
2934
    }
2935

2936
    /// Get the second component of a vector.
2937
    ///
2938
    /// # Example
2939
    ///
2940
    /// ```
2941
    /// # use bevy_hanabi::*;
2942
    /// # use bevy::math::Vec3;
2943
    /// # let mut w = ExprWriter::new();
2944
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
2945
    /// let v = w.lit(Vec3::ONE);
2946
    ///
2947
    /// // f = v.y;`
2948
    /// let f = v.y();
2949
    /// ```
2950
    #[inline]
2951
    pub fn y(self) -> Self {
×
2952
        self.unary_op(UnaryOperator::Y)
×
2953
    }
2954

2955
    /// Get the third component of a vector.
2956
    ///
2957
    /// # Example
2958
    ///
2959
    /// ```
2960
    /// # use bevy_hanabi::*;
2961
    /// # use bevy::math::Vec3;
2962
    /// # let mut w = ExprWriter::new();
2963
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
2964
    /// let v = w.lit(Vec3::ONE);
2965
    ///
2966
    /// // f = v.z;`
2967
    /// let f = v.z();
2968
    /// ```
2969
    #[inline]
2970
    pub fn z(self) -> Self {
×
2971
        self.unary_op(UnaryOperator::Z)
×
2972
    }
2973

2974
    /// Get the fourth component of a vector.
2975
    ///
2976
    /// # Example
2977
    ///
2978
    /// ```
2979
    /// # use bevy_hanabi::*;
2980
    /// # use bevy::math::Vec3;
2981
    /// # let mut w = ExprWriter::new();
2982
    /// // A literal expression `v = vec3<f32>(1., 1., 1.);`.
2983
    /// let v = w.lit(Vec3::ONE);
2984
    ///
2985
    /// // f = v.w;`
2986
    /// let f = v.w();
2987
    /// ```
2988
    #[inline]
2989
    pub fn w(self) -> Self {
×
2990
        self.unary_op(UnaryOperator::W)
×
2991
    }
2992

2993
    fn binary_op(self, other: Self, op: BinaryOperator) -> Self {
5✔
2994
        assert_eq!(self.module, other.module);
5✔
2995
        let left = self.expr;
5✔
2996
        let right = other.expr;
5✔
2997
        let expr = self
5✔
2998
            .module
5✔
2999
            .borrow_mut()
3000
            .push(Expr::Binary { op, left, right });
5✔
3001
        WriterExpr {
3002
            expr,
3003
            module: self.module,
5✔
3004
        }
3005
    }
3006

3007
    /// Add the current expression with another expression.
3008
    ///
3009
    /// This is a binary operator, which applies component-wise to vector
3010
    /// operand expressions.
3011
    ///
3012
    /// You can also use the [`std::ops::Add`] trait directly, via the `+`
3013
    /// symbol, as an alternative to calling this method directly.
3014
    ///
3015
    /// # Example
3016
    ///
3017
    /// ```
3018
    /// # use bevy_hanabi::*;
3019
    /// # use bevy::math::Vec2;
3020
    /// # let mut w = ExprWriter::new();
3021
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3022
    /// let x = w.lit(Vec2::new(3., -2.));
3023
    ///
3024
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3025
    /// let y = w.lit(Vec2::new(1., 5.));
3026
    ///
3027
    /// // The sum of both vectors `z = x + y;`.
3028
    /// let z = x.add(y); // == vec2<f32>(4., 3.)
3029
    ///                   // -OR-
3030
    ///                   // let z = x + y;
3031
    /// ```
3032
    #[allow(clippy::should_implement_trait)]
3033
    #[inline]
3034
    pub fn add(self, other: Self) -> Self {
2✔
3035
        self.binary_op(other, BinaryOperator::Add)
2✔
3036
    }
3037

3038
    /// Calculate the cross product of the current expression by another
3039
    /// expression.
3040
    ///
3041
    /// This is a binary operator, which applies to vector operands of size 3
3042
    /// only, and always produces a vector of the same size.
3043
    ///
3044
    /// # Example
3045
    ///
3046
    /// ```
3047
    /// # use bevy_hanabi::*;
3048
    /// # use bevy::math::Vec3;
3049
    /// # let mut w = ExprWriter::new();
3050
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3051
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3052
    ///
3053
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3054
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3055
    ///
3056
    /// // The cross product of both vectors `z = cross(x, y);`.
3057
    /// let z = x.cross(y);
3058
    /// ```
3059
    #[inline]
3060
    pub fn cross(self, other: Self) -> Self {
×
3061
        self.binary_op(other, BinaryOperator::Cross)
×
3062
    }
3063

3064
    /// Calculate the dot product of the current expression by another
3065
    /// expression.
3066
    ///
3067
    /// This is a binary operator, which applies to vector operands of same size
3068
    /// only, and always produces a floating point scalar.
3069
    ///
3070
    /// # Example
3071
    ///
3072
    /// ```
3073
    /// # use bevy_hanabi::*;
3074
    /// # use bevy::math::Vec2;
3075
    /// # let mut w = ExprWriter::new();
3076
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3077
    /// let x = w.lit(Vec2::new(3., -2.));
3078
    ///
3079
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3080
    /// let y = w.lit(Vec2::new(1., 5.));
3081
    ///
3082
    /// // The dot product of both vectors `z = dot(x, y);`.
3083
    /// let z = x.dot(y);
3084
    /// ```
3085
    #[inline]
3086
    pub fn dot(self, other: Self) -> Self {
×
3087
        self.binary_op(other, BinaryOperator::Dot)
×
3088
    }
3089

3090
    /// Calculate the distance between the current expression and another
3091
    /// expression.
3092
    ///
3093
    /// This is a binary operator.
3094
    ///
3095
    /// # Example
3096
    ///
3097
    /// ```
3098
    /// # use bevy_hanabi::*;
3099
    /// # use bevy::math::Vec3;
3100
    /// # let mut w = ExprWriter::new();
3101
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3102
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3103
    ///
3104
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3105
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3106
    ///
3107
    /// // The distance between the vectors `z = distance(x, y);`.
3108
    /// let z = x.distance(y);
3109
    /// ```
3110
    #[inline]
3111
    pub fn distance(self, other: Self) -> Self {
×
3112
        self.binary_op(other, BinaryOperator::Distance)
×
3113
    }
3114

3115
    /// Divide the current expression by another expression.
3116
    ///
3117
    /// This is a binary operator, which applies component-wise to vector
3118
    /// operand expressions.
3119
    ///
3120
    /// You can also use the [`std::ops::Div`] trait directly, via the `/`
3121
    /// symbol, as an alternative to calling this method directly.
3122
    ///
3123
    /// # Example
3124
    ///
3125
    /// ```
3126
    /// # use bevy_hanabi::*;
3127
    /// # use bevy::math::Vec2;
3128
    /// # let mut w = ExprWriter::new();
3129
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3130
    /// let x = w.lit(Vec2::new(3., -2.));
3131
    ///
3132
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3133
    /// let y = w.lit(Vec2::new(1., 5.));
3134
    ///
3135
    /// // The quotient of both vectors `z = x / y;`.
3136
    /// let z = x.div(y); // == vec2<f32>(3., -0.4)
3137
    ///                   // -OR-
3138
    ///                   // let z = x / y;
3139
    /// ```
3140
    #[allow(clippy::should_implement_trait)]
3141
    #[inline]
3142
    pub fn div(self, other: Self) -> Self {
×
3143
        self.binary_op(other, BinaryOperator::Div)
×
3144
    }
3145

3146
    /// Apply the logical operator "greater than or equal" to this expression
3147
    /// and another expression.
3148
    ///
3149
    /// This is a binary operator, which applies component-wise to vector
3150
    /// operand expressions.
3151
    ///
3152
    /// # Example
3153
    ///
3154
    /// ```
3155
    /// # use bevy_hanabi::*;
3156
    /// # use bevy::math::Vec3;
3157
    /// # let mut w = ExprWriter::new();
3158
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3159
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3160
    ///
3161
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3162
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3163
    ///
3164
    /// // The boolean result of the greater than or equal operation `z = (x >= y);`.
3165
    /// let z = x.ge(y); // == vec3<bool>(true, false, true)
3166
    /// ```
3167
    #[inline]
3168
    pub fn ge(self, other: Self) -> Self {
×
3169
        self.binary_op(other, BinaryOperator::GreaterThanOrEqual)
×
3170
    }
3171

3172
    /// Apply the logical operator "greater than" to this expression and another
3173
    /// expression.
3174
    ///
3175
    /// This is a binary operator, which applies component-wise to vector
3176
    /// operand expressions.
3177
    ///
3178
    /// # Example
3179
    ///
3180
    /// ```
3181
    /// # use bevy_hanabi::*;
3182
    /// # use bevy::math::Vec3;
3183
    /// # let mut w = ExprWriter::new();
3184
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3185
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3186
    ///
3187
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3188
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3189
    ///
3190
    /// // The boolean result of the greater than operation `z = (x > y);`.
3191
    /// let z = x.gt(y); // == vec3<bool>(true, false, false)
3192
    /// ```
3193
    #[inline]
3194
    pub fn gt(self, other: Self) -> Self {
×
3195
        self.binary_op(other, BinaryOperator::GreaterThan)
×
3196
    }
3197

3198
    /// Apply the logical operator "less than or equal" to this expression and
3199
    /// another expression.
3200
    ///
3201
    /// This is a binary operator, which applies component-wise to vector
3202
    /// operand expressions.
3203
    ///
3204
    /// # Example
3205
    ///
3206
    /// ```
3207
    /// # use bevy_hanabi::*;
3208
    /// # use bevy::math::Vec3;
3209
    /// # let mut w = ExprWriter::new();
3210
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3211
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3212
    ///
3213
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3214
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3215
    ///
3216
    /// // The boolean result of the less than or equal operation `z = (x <= y);`.
3217
    /// let z = x.le(y); // == vec3<bool>(false, true, true)
3218
    /// ```
3219
    #[inline]
3220
    pub fn le(self, other: Self) -> Self {
×
3221
        self.binary_op(other, BinaryOperator::LessThanOrEqual)
×
3222
    }
3223

3224
    /// Apply the logical operator "less than" to this expression and another
3225
    /// expression.
3226
    ///
3227
    /// This is a binary operator, which applies component-wise to vector
3228
    /// operand expressions.
3229
    ///
3230
    /// # Example
3231
    ///
3232
    /// ```
3233
    /// # use bevy_hanabi::*;
3234
    /// # use bevy::math::Vec3;
3235
    /// # let mut w = ExprWriter::new();
3236
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3237
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3238
    ///
3239
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3240
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3241
    ///
3242
    /// // The boolean result of the less than operation `z = (x < y);`.
3243
    /// let z = x.lt(y); // == vec3<bool>(false, true, false)
3244
    /// ```
3245
    #[inline]
3246
    pub fn lt(self, other: Self) -> Self {
×
3247
        self.binary_op(other, BinaryOperator::LessThan)
×
3248
    }
3249

3250
    /// Take the maximum value of the current expression and another expression.
3251
    ///
3252
    /// This is a binary operator, which applies component-wise to vector
3253
    /// operand expressions.
3254
    ///
3255
    /// # Example
3256
    ///
3257
    /// ```
3258
    /// # use bevy_hanabi::*;
3259
    /// # use bevy::math::Vec2;
3260
    /// # let mut w = ExprWriter::new();
3261
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3262
    /// let x = w.lit(Vec2::new(3., -2.));
3263
    ///
3264
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3265
    /// let y = w.lit(Vec2::new(1., 5.));
3266
    ///
3267
    /// // The maximum of both vectors `z = max(x, y);`.
3268
    /// let z = x.max(y); // == vec2<f32>(3., 5.)
3269
    /// ```
3270
    #[inline]
3271
    pub fn max(self, other: Self) -> Self {
1✔
3272
        self.binary_op(other, BinaryOperator::Max)
1✔
3273
    }
3274

3275
    /// Take the minimum value of the current expression and another expression.
3276
    ///
3277
    /// This is a binary operator, which applies component-wise to vector
3278
    /// operand expressions.
3279
    ///
3280
    /// # Example
3281
    ///
3282
    /// ```
3283
    /// # use bevy_hanabi::*;
3284
    /// # use bevy::math::Vec2;
3285
    /// # let mut w = ExprWriter::new();
3286
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3287
    /// let x = w.lit(Vec2::new(3., -2.));
3288
    ///
3289
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3290
    /// let y = w.lit(Vec2::new(1., 5.));
3291
    ///
3292
    /// // The minimum of both vectors `z = min(x, y);`.
3293
    /// let z = x.min(y); // == vec2<f32>(1., -2.)
3294
    /// ```
3295
    #[inline]
3296
    pub fn min(self, other: Self) -> Self {
1✔
3297
        self.binary_op(other, BinaryOperator::Min)
1✔
3298
    }
3299

3300
    /// Multiply the current expression with another expression.
3301
    ///
3302
    /// This is a binary operator, which applies component-wise to vector
3303
    /// operand expressions.
3304
    ///
3305
    /// You can also use the [`std::ops::Mul`] trait directly, via the `*`
3306
    /// symbol, as an alternative to calling this method directly.
3307
    ///
3308
    /// # Example
3309
    ///
3310
    /// ```
3311
    /// # use bevy_hanabi::*;
3312
    /// # use bevy::math::Vec2;
3313
    /// # let mut w = ExprWriter::new();
3314
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3315
    /// let x = w.lit(Vec2::new(3., -2.));
3316
    ///
3317
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3318
    /// let y = w.lit(Vec2::new(1., 5.));
3319
    ///
3320
    /// // The product of both vectors `z = x * y;`.
3321
    /// let z = x.mul(y); // == vec2<f32>(3., -10.)
3322
    ///                   // -OR-
3323
    ///                   // let z = x * y;
3324
    /// ```
3325
    #[allow(clippy::should_implement_trait)]
3326
    #[inline]
3327
    pub fn mul(self, other: Self) -> Self {
1✔
3328
        self.binary_op(other, BinaryOperator::Mul)
1✔
3329
    }
3330

3331
    /// Calculate the remainder of the division of the current expression by
3332
    /// another expression.
3333
    ///
3334
    /// This is a binary operator.
3335
    ///
3336
    /// # Example
3337
    ///
3338
    /// ```
3339
    /// # use bevy_hanabi::*;
3340
    /// # use bevy::math::Vec3;
3341
    /// # let mut w = ExprWriter::new();
3342
    /// // A literal expression `x = vec3<f32>(3., -2., 1.);`.
3343
    /// let x = w.lit(Vec3::new(3., -2., 1.));
3344
    ///
3345
    /// // Another literal expression `y = vec3<f32>(1., 5., 0.);`.
3346
    /// let y = w.lit(Vec3::new(1., 5., 0.));
3347
    ///
3348
    /// // The remainder of the division `z = x % y;`.
3349
    /// let z = x.rem(y);
3350
    /// ```
3351
    #[allow(clippy::should_implement_trait)]
3352
    #[inline]
3353
    pub fn rem(self, other: Self) -> Self {
×
3354
        self.binary_op(other, BinaryOperator::Remainder)
×
3355
    }
3356

3357
    /// Calculate the step of a value with respect to a reference.
3358
    ///
3359
    /// This is a binary operator, which applies component-wise to vector
3360
    /// operand expressions.
3361
    ///
3362
    /// # Example
3363
    ///
3364
    /// ```
3365
    /// # use bevy_hanabi::*;
3366
    /// # use bevy::math::Vec3;
3367
    /// # let mut w = ExprWriter::new();
3368
    /// // A literal expression `x = vec3<f32>(3., -2.);`.
3369
    /// let x = w.lit(Vec3::new(3., -2., 8.));
3370
    ///
3371
    /// // An edge reference `e = vec3<f32>(1., 5.);`.
3372
    /// let e = w.lit(Vec3::new(1., 5., 8.));
3373
    ///
3374
    /// // The step value
3375
    /// let s = x.step(e); // == vec3<f32>(1., 0., 1.)
3376
    /// ```
3377
    #[allow(clippy::should_implement_trait)]
3378
    #[inline]
3379
    pub fn step(self, edge: Self) -> Self {
×
3380
        // Note: order is step(edge, x) but x.step(edge)
3381
        edge.binary_op(self, BinaryOperator::Step)
×
3382
    }
3383

3384
    /// Subtract another expression from the current expression.
3385
    ///
3386
    /// This is a binary operator, which applies component-wise to vector
3387
    /// operand expressions.
3388
    ///
3389
    /// You can also use the [`std::ops::Sub`] trait directly, via the `-`
3390
    /// symbol, as an alternative to calling this method directly.
3391
    ///
3392
    /// # Example
3393
    ///
3394
    /// ```
3395
    /// # use bevy_hanabi::*;
3396
    /// # use bevy::math::Vec2;
3397
    /// # let mut w = ExprWriter::new();
3398
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3399
    /// let x = w.lit(Vec2::new(3., -2.));
3400
    ///
3401
    /// // Another literal expression `y = vec2<f32>(1., 5.);`.
3402
    /// let y = w.lit(Vec2::new(1., 5.));
3403
    ///
3404
    /// // The difference of both vectors `z = x - y;`.
3405
    /// let z = x.sub(y); // == vec2<f32>(2., -7.)
3406
    ///                   // -OR-
3407
    ///                   // let z = x - y;
3408
    /// ```
3409
    #[allow(clippy::should_implement_trait)]
3410
    #[inline]
3411
    pub fn sub(self, other: Self) -> Self {
×
3412
        self.binary_op(other, BinaryOperator::Sub)
×
3413
    }
3414

3415
    /// Apply the logical operator "uniform" to this expression and another
3416
    /// expression.
3417
    ///
3418
    /// This is a binary operator, which applies component-wise to vector
3419
    /// operand expressions. That is, for vectors, this produces a vector of
3420
    /// random values where each component is uniformly distributed within the
3421
    /// bounds of the related component of both operands.
3422
    ///
3423
    /// # Example
3424
    ///
3425
    /// ```
3426
    /// # use bevy_hanabi::*;
3427
    /// # use bevy::math::Vec3;
3428
    /// # let mut w = ExprWriter::new();
3429
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3430
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3431
    ///
3432
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3433
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3434
    ///
3435
    /// // A random variable uniformly distributed in [1:3]x[-2:5]x[7:7].
3436
    /// let z = x.uniform(y);
3437
    /// ```
3438
    #[inline]
3439
    pub fn uniform(self, other: Self) -> Self {
×
3440
        self.binary_op(other, BinaryOperator::UniformRand)
×
3441
    }
3442

3443
    /// Apply the logical operator "normal" to this expression and another
3444
    /// expression.
3445
    ///
3446
    /// This is a binary operator, which applies component-wise to vector
3447
    /// operand expressions. That is, for vectors, this produces a vector of
3448
    /// random values where each component is normally distributed with a mean
3449
    /// of the corresponding component of the first operand and a standard
3450
    /// deviation of the corresponding component of the second operand.
3451
    ///
3452
    /// # Example
3453
    ///
3454
    /// ```
3455
    /// # use bevy_hanabi::*;
3456
    /// # use bevy::math::Vec3;
3457
    /// # let mut w = ExprWriter::new();
3458
    /// // A literal expression `x = vec3<f32>(3., -2., 7.);`.
3459
    /// let x = w.lit(Vec3::new(3., -2., 7.));
3460
    ///
3461
    /// // Another literal expression `y = vec3<f32>(1., 5., 7.);`.
3462
    /// let y = w.lit(Vec3::new(1., 5., 7.));
3463
    ///
3464
    /// // A random variable normally distributed in [1:3]x[-2:5]x[7:7].
3465
    /// let z = x.normal(y);
3466
    /// ```
3467
    #[inline]
NEW
3468
    pub fn normal(self, other: Self) -> Self {
×
NEW
3469
        self.binary_op(other, BinaryOperator::NormalRand)
×
3470
    }
3471

3472
    fn ternary_op(self, second: Self, third: Self, op: TernaryOperator) -> Self {
×
3473
        assert_eq!(self.module, second.module);
×
3474
        assert_eq!(self.module, third.module);
×
3475
        let first = self.expr;
×
3476
        let second = second.expr;
×
3477
        let third = third.expr;
×
3478
        let expr = self.module.borrow_mut().push(Expr::Ternary {
×
3479
            op,
×
3480
            first,
×
3481
            second,
×
3482
            third,
×
3483
        });
3484
        WriterExpr {
3485
            expr,
3486
            module: self.module,
×
3487
        }
3488
    }
3489

3490
    /// Blending linearly ("mix") two expressions with the fraction provided by
3491
    /// a third expression.
3492
    ///
3493
    /// This is a ternary operator, which applies component-wise to vector
3494
    /// operand expressions.
3495
    ///
3496
    /// # Example
3497
    ///
3498
    /// ```
3499
    /// # use bevy_hanabi::*;
3500
    /// # use bevy::math::Vec2;
3501
    /// # let mut w = ExprWriter::new();
3502
    /// // A literal expression `x = vec2<f32>(3., -2.);`.
3503
    /// let x = w.lit(Vec2::new(3., -2.));
3504
    ///
3505
    /// // Another literal expression `y = vec2<f32>(1., 4.);`.
3506
    /// let y = w.lit(Vec2::new(1., 4.));
3507
    ///
3508
    /// // A fraction `t = 0.5;`.
3509
    /// let t = w.lit(0.25);
3510
    ///
3511
    /// // The linear blend of x and y via t: z = (1 - t) * x + y * t
3512
    /// let z = x.mix(y, t); // == vec2<f32>(2.5, -0.5)
3513
    /// ```
3514
    #[inline]
3515
    pub fn mix(self, other: Self, fraction: Self) -> Self {
×
3516
        self.ternary_op(other, fraction, TernaryOperator::Mix)
×
3517
    }
3518

3519
    /// Calculate the smooth Hermite interpolation in \[0:1\] of the current
3520
    /// value taken between the given bounds.
3521
    ///
3522
    /// This is a ternary operator, which applies component-wise to vector
3523
    /// operand expressions.
3524
    ///
3525
    /// # Example
3526
    ///
3527
    /// ```
3528
    /// # use bevy_hanabi::*;
3529
    /// # use bevy::math::Vec2;
3530
    /// # let mut w = ExprWriter::new();
3531
    /// // A literal expression `low = vec2<f32>(3., -2.);`.
3532
    /// let low = w.lit(Vec2::new(3., -2.));
3533
    ///
3534
    /// // Another literal expression `high = vec2<f32>(1., 4.);`.
3535
    /// let high = w.lit(Vec2::new(1., 4.));
3536
    ///
3537
    /// // A point `x = vec2<f32>(2., 1.);` between `low` and `high`.
3538
    /// let x = w.lit(Vec2::new(2., 1.));
3539
    ///
3540
    /// // The smooth Hermite interpolation: `t = smoothstep(low, high, x)`
3541
    /// let t = x.smoothstep(low, high); // == 0.5
3542
    /// ```
3543
    #[inline]
3544
    pub fn smoothstep(self, low: Self, high: Self) -> Self {
×
3545
        // Note: order is smoothstep(low, high, x) but x.smoothstep(low, high)
3546
        low.ternary_op(high, self, TernaryOperator::SmoothStep)
×
3547
    }
3548

3549
    /// Construct a `Vec2` from two scalars.
3550
    ///
3551
    /// # Example
3552
    ///
3553
    /// ```
3554
    /// # use bevy_hanabi::*;
3555
    /// # let mut w = ExprWriter::new();
3556
    /// let theta = w.add_property("theta", 0.0.into());
3557
    /// // Convert the angular property `theta` to a 2D vector.
3558
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3559
    /// let circle_pos = cos_theta.vec2(sin_theta);
3560
    /// ```
3561
    #[inline]
3562
    pub fn vec2(self, y: Self) -> Self {
×
3563
        self.binary_op(y, BinaryOperator::Vec2)
×
3564
    }
3565

3566
    /// Construct a `Vec3` from two scalars.
3567
    ///
3568
    /// # Example
3569
    ///
3570
    /// ```
3571
    /// # use bevy_hanabi::*;
3572
    /// # let mut w = ExprWriter::new();
3573
    /// let theta = w.add_property("theta", 0.0.into());
3574
    /// // Convert the angular property `theta` to a 3D vector in a flat plane.
3575
    /// let (cos_theta, sin_theta) = (w.prop(theta).cos(), w.prop(theta).sin());
3576
    /// let circle_pos = cos_theta.vec3(w.lit(0.0), sin_theta);
3577
    /// ```
3578
    #[inline]
3579
    pub fn vec3(self, y: Self, z: Self) -> Self {
×
3580
        self.ternary_op(y, z, TernaryOperator::Vec3)
×
3581
    }
3582

3583
    /// Cast an expression to a different type.
3584
    ///
3585
    /// # Example
3586
    ///
3587
    /// ```
3588
    /// # use bevy_hanabi::*;
3589
    /// # use bevy::math::Vec2;
3590
    /// # let mut w = ExprWriter::new();
3591
    /// let x = w.lit(Vec2::new(3., -2.));
3592
    /// let y = x.cast(VectorType::VEC3I); // x = vec3<i32>(particle.position);
3593
    /// ```
3594
    pub fn cast(self, target: impl Into<ValueType>) -> Self {
×
3595
        let target = target.into();
×
3596
        let expr = self
×
3597
            .module
×
3598
            .borrow_mut()
3599
            .push(Expr::Cast(CastExpr::new(self.expr, target)));
×
3600
        WriterExpr {
3601
            expr,
3602
            module: self.module,
×
3603
        }
3604
    }
3605

3606
    /// Finalize an expression chain and return the accumulated expression.
3607
    ///
3608
    /// The returned handle indexes the [`Module`] owned by the [`ExprWriter`]
3609
    /// this intermediate expression was built from.
3610
    ///
3611
    /// # Example
3612
    ///
3613
    /// ```
3614
    /// # use bevy_hanabi::*;
3615
    /// # let mut w = ExprWriter::new();
3616
    /// // A literal expression `x = -3.5;`.
3617
    /// let x = w.lit(-3.5);
3618
    ///
3619
    /// // Retrieve the ExprHandle for that expression.
3620
    /// let handle = x.expr();
3621
    /// ```
3622
    #[inline]
3623
    pub fn expr(self) -> ExprHandle {
8✔
3624
        self.expr
8✔
3625
    }
3626
}
3627

3628
impl std::ops::Add<WriterExpr> for WriterExpr {
3629
    type Output = WriterExpr;
3630

3631
    #[inline]
3632
    fn add(self, rhs: WriterExpr) -> Self::Output {
2✔
3633
        self.add(rhs)
2✔
3634
    }
3635
}
3636

3637
impl std::ops::Sub<WriterExpr> for WriterExpr {
3638
    type Output = WriterExpr;
3639

3640
    #[inline]
3641
    fn sub(self, rhs: WriterExpr) -> Self::Output {
×
3642
        self.sub(rhs)
×
3643
    }
3644
}
3645

3646
impl std::ops::Mul<WriterExpr> for WriterExpr {
3647
    type Output = WriterExpr;
3648

3649
    #[inline]
3650
    fn mul(self, rhs: WriterExpr) -> Self::Output {
1✔
3651
        self.mul(rhs)
1✔
3652
    }
3653
}
3654

3655
impl std::ops::Div<WriterExpr> for WriterExpr {
3656
    type Output = WriterExpr;
3657

3658
    #[inline]
3659
    fn div(self, rhs: WriterExpr) -> Self::Output {
×
3660
        self.div(rhs)
×
3661
    }
3662
}
3663

3664
impl std::ops::Rem<WriterExpr> for WriterExpr {
3665
    type Output = WriterExpr;
3666

3667
    #[inline]
3668
    fn rem(self, rhs: WriterExpr) -> Self::Output {
×
3669
        self.rem(rhs)
×
3670
    }
3671
}
3672

3673
#[cfg(test)]
3674
mod tests {
3675
    use bevy::{prelude::*, utils::HashSet};
3676

3677
    use super::*;
3678
    use crate::{MatrixType, ScalarValue, ShaderWriter, VectorType};
3679

3680
    #[test]
3681
    fn module() {
3682
        let mut m = Module::default();
3683

3684
        #[allow(unsafe_code)]
3685
        let unknown = unsafe { ExprHandle::new_unchecked(1) };
3686
        assert!(m.get(unknown).is_none());
3687
        assert!(m.get_mut(unknown).is_none());
3688
        assert!(matches!(
3689
            m.try_get(unknown),
3690
            Err(ExprError::InvalidExprHandleError(_))
3691
        ));
3692
        assert!(matches!(
3693
            m.try_get_mut(unknown),
3694
            Err(ExprError::InvalidExprHandleError(_))
3695
        ));
3696

3697
        let x = m.lit(5.);
3698
        let mut expected = Expr::Literal(LiteralExpr::new(5.));
3699
        assert_eq!(m.get(x), Some(&expected));
3700
        assert_eq!(m.get_mut(x), Some(&mut expected));
3701
        assert_eq!(m.try_get(x), Ok(&expected));
3702
        assert_eq!(m.try_get_mut(x), Ok(&mut expected));
3703
    }
3704

3705
    #[test]
3706
    fn local_var() {
3707
        let property_layout = PropertyLayout::default();
3708
        let particle_layout = ParticleLayout::default();
3709
        let mut ctx =
3710
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3711
        let mut h = HashSet::new();
3712
        for _ in 0..100 {
3713
            let v = ctx.make_local_var();
3714
            assert!(h.insert(v));
3715
        }
3716
    }
3717

3718
    #[test]
3719
    fn make_fn() {
3720
        let property_layout = PropertyLayout::default();
3721
        let particle_layout = ParticleLayout::default();
3722
        let mut ctx =
3723
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3724
        let mut module = Module::default();
3725

3726
        // Make a function
3727
        let func_name = "my_func";
3728
        let args = "arg0: i32, arg1: f32";
3729
        assert!(ctx
3730
            .make_fn(func_name, args, &mut module, &mut |m, ctx| {
3731
                m.lit(3.);
3732
                let v = ctx.make_local_var();
3733
                assert_eq!(v, "var0");
3734
                let code = String::new();
3735
                Ok(code)
3736
            })
3737
            .is_ok());
3738

3739
        // The local function context doesn't influence the outer caller context
3740
        let v = ctx.make_local_var();
3741
        assert_eq!(v, "var0");
3742

3743
        // However the module is common to the outer caller and the function
3744
        assert!(!module.expressions.is_empty());
3745
    }
3746

3747
    #[test]
3748
    fn property() {
3749
        let mut m = Module::default();
3750

3751
        let _my_prop = m.add_property("my_prop", Value::Scalar(345_u32.into()));
3752
        let _other_prop = m.add_property(
3753
            "other_prop",
3754
            Value::Vector(Vec3::new(3., -7.5, 42.42).into()),
3755
        );
3756

3757
        assert!(m.properties().iter().any(|p| p.name() == "my_prop"));
3758
        assert!(m.properties().iter().any(|p| p.name() == "other_prop"));
3759
        assert!(!m.properties().iter().any(|p| p.name() == "do_not_exist"));
3760
    }
3761

3762
    #[test]
3763
    fn writer() {
3764
        // Get a module and its writer
3765
        let w = ExprWriter::new();
3766
        let my_prop = w.add_property("my_prop", 3.0.into());
3767

3768
        // Build some expression
3769
        let x = w.lit(3.).abs().max(w.attr(Attribute::POSITION) * w.lit(2.))
3770
            + w.lit(-4.).min(w.prop(my_prop));
3771
        let x = x.expr();
3772

3773
        // Create an evaluation context
3774
        let property_layout =
3775
            PropertyLayout::new(&[Property::new("my_prop", ScalarValue::Float(3.))]);
3776
        let particle_layout = ParticleLayout::default();
3777
        let m = w.finish();
3778
        let mut context =
3779
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3780

3781
        // Evaluate the expression
3782
        let x = m.try_get(x).unwrap();
3783
        let s = x.eval(&m, &mut context).unwrap();
3784
        assert_eq!(
3785
            "(max(abs(3.), (particle.position) * (2.))) + (min(-4., properties.my_prop))"
3786
                .to_string(),
3787
            s
3788
        );
3789
    }
3790

3791
    #[test]
3792
    fn type_error() {
3793
        let l = Value::Scalar(3.5_f32.into());
3794
        let r: Result<Vec2, ExprError> = l.try_into();
3795
        assert!(r.is_err());
3796
        assert!(matches!(r, Err(ExprError::TypeError(_))));
3797
    }
3798

3799
    #[test]
3800
    fn math_expr() {
3801
        let mut m = Module::default();
3802

3803
        let x = m.attr(Attribute::POSITION);
3804
        let y = m.lit(Vec3::ONE);
3805

3806
        let add = m.add(x, y);
3807
        let sub = m.sub(x, y);
3808
        let mul = m.mul(x, y);
3809
        let div = m.div(x, y);
3810
        let rem = m.rem(x, y);
3811
        let lt = m.lt(x, y);
3812
        let le = m.le(x, y);
3813
        let gt = m.gt(x, y);
3814
        let ge = m.ge(x, y);
3815

3816
        let property_layout = PropertyLayout::default();
3817
        let particle_layout = ParticleLayout::default();
3818
        let mut ctx =
3819
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3820

3821
        for (expr, op) in [
3822
            (add, "+"),
3823
            (sub, "-"),
3824
            (mul, "*"),
3825
            (div, "/"),
3826
            (rem, "%"),
3827
            (lt, "<"),
3828
            (le, "<="),
3829
            (gt, ">"),
3830
            (ge, ">="),
3831
        ] {
3832
            let expr = ctx.eval(&m, expr);
3833
            assert!(expr.is_ok());
3834
            let expr = expr.unwrap();
3835
            assert_eq!(
3836
                expr,
3837
                format!(
3838
                    "(particle.{}) {} (vec3<f32>(1.,1.,1.))",
3839
                    Attribute::POSITION.name(),
3840
                    op,
3841
                )
3842
            );
3843
        }
3844
    }
3845

3846
    #[test]
3847
    fn builtin_expr() {
3848
        let mut m = Module::default();
3849

3850
        // Simulation parameters
3851
        for op in [
3852
            BuiltInOperator::Time,
3853
            BuiltInOperator::DeltaTime,
3854
            BuiltInOperator::VirtualTime,
3855
            BuiltInOperator::VirtualDeltaTime,
3856
            BuiltInOperator::RealTime,
3857
            BuiltInOperator::RealDeltaTime,
3858
        ] {
3859
            let value = m.builtin(op);
3860

3861
            let property_layout = PropertyLayout::default();
3862
            let particle_layout = ParticleLayout::default();
3863
            let mut ctx =
3864
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3865

3866
            let expr = ctx.eval(&m, value);
3867
            assert!(expr.is_ok());
3868
            let expr = expr.unwrap();
3869
            assert_eq!(expr, format!("sim_params.{}", op.name()));
3870
        }
3871

3872
        // is_alive
3873
        {
3874
            let value = m.builtin(BuiltInOperator::IsAlive);
3875

3876
            let property_layout = PropertyLayout::default();
3877
            let particle_layout = ParticleLayout::default();
3878
            let mut ctx =
3879
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3880

3881
            let expr = ctx.eval(&m, value);
3882
            assert!(expr.is_ok());
3883
            let expr = expr.unwrap();
3884
            assert_eq!(expr, "is_alive");
3885
        }
3886

3887
        // BuiltInOperator::Rand (which has side effect)
3888
        for (scalar_type, prefix) in [
3889
            (ScalarType::Bool, "b"),
3890
            (ScalarType::Float, "f"),
3891
            (ScalarType::Int, "i"),
3892
            (ScalarType::Uint, "u"),
3893
        ] {
3894
            let value = m.builtin(BuiltInOperator::Rand(scalar_type.into()));
3895

3896
            // Scalar form
3897
            {
3898
                let property_layout = PropertyLayout::default();
3899
                let particle_layout = ParticleLayout::default();
3900
                let mut ctx =
3901
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3902

3903
                let expr = ctx.eval(&m, value);
3904
                assert!(expr.is_ok());
3905
                let expr = expr.unwrap();
3906
                assert_eq!(expr, "var0");
3907
                assert_eq!(ctx.main_code, format!("let var0 = {}rand();\n", prefix));
3908
            }
3909

3910
            // Vector form
3911
            for count in 2..=4 {
3912
                let vec = m.builtin(BuiltInOperator::Rand(
3913
                    VectorType::new(scalar_type, count).into(),
3914
                ));
3915

3916
                let property_layout = PropertyLayout::default();
3917
                let particle_layout = ParticleLayout::default();
3918
                let mut ctx =
3919
                    ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3920

3921
                let expr = ctx.eval(&m, vec);
3922
                assert!(expr.is_ok());
3923
                let expr = expr.unwrap();
3924
                assert_eq!(expr, "var0");
3925
                assert_eq!(
3926
                    ctx.main_code,
3927
                    format!("let var0 = {}rand{}();\n", prefix, count)
3928
                );
3929
            }
3930
        }
3931
    }
3932

3933
    #[test]
3934
    fn unary_expr() {
3935
        let mut m = Module::default();
3936

3937
        let x = m.attr(Attribute::POSITION);
3938
        let y = m.lit(Vec3::new(1., -3.1, 6.99));
3939
        let z = m.lit(BVec3::new(false, true, false));
3940
        let w = m.lit(Vec4::W);
3941
        let v = m.lit(Vec4::new(-1., 1., 0., 7.2));
3942
        let us = m.lit(0x0u32);
3943
        let uu = m.lit(0x0u32);
3944

3945
        let abs = m.abs(x);
3946
        let all = m.all(z);
3947
        let any = m.any(z);
3948
        let ceil = m.ceil(y);
3949
        let cos = m.cos(y);
3950
        let exp = m.exp(y);
3951
        let exp2 = m.exp2(y);
3952
        let floor = m.floor(y);
3953
        let fract = m.fract(y);
3954
        let inv_sqrt = m.inverse_sqrt(y);
3955
        let length = m.length(y);
3956
        let log = m.log(y);
3957
        let log2 = m.log2(y);
3958
        let norm = m.normalize(y);
3959
        let pack4x8snorm = m.pack4x8snorm(v);
3960
        let pack4x8unorm = m.pack4x8unorm(v);
3961
        let saturate = m.saturate(y);
3962
        let sign = m.sign(y);
3963
        let sin = m.sin(y);
3964
        let sqrt = m.sqrt(y);
3965
        let tan = m.tan(y);
3966
        let unpack4x8snorm = m.unpack4x8snorm(us);
3967
        let unpack4x8unorm = m.unpack4x8unorm(uu);
3968
        let comp_x = m.x(w);
3969
        let comp_y = m.y(w);
3970
        let comp_z = m.z(w);
3971
        let comp_w = m.w(w);
3972

3973
        let property_layout = PropertyLayout::default();
3974
        let particle_layout = ParticleLayout::default();
3975
        let mut ctx =
3976
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
3977

3978
        for (expr, op, inner) in [
3979
            (
3980
                abs,
3981
                "abs",
3982
                &format!("particle.{}", Attribute::POSITION.name())[..],
3983
            ),
3984
            (all, "all", "vec3<bool>(false,true,false)"),
3985
            (any, "any", "vec3<bool>(false,true,false)"),
3986
            (ceil, "ceil", "vec3<f32>(1.,-3.1,6.99)"),
3987
            (cos, "cos", "vec3<f32>(1.,-3.1,6.99)"),
3988
            (exp, "exp", "vec3<f32>(1.,-3.1,6.99)"),
3989
            (exp2, "exp2", "vec3<f32>(1.,-3.1,6.99)"),
3990
            (floor, "floor", "vec3<f32>(1.,-3.1,6.99)"),
3991
            (fract, "fract", "vec3<f32>(1.,-3.1,6.99)"),
3992
            (inv_sqrt, "inverseSqrt", "vec3<f32>(1.,-3.1,6.99)"),
3993
            (length, "length", "vec3<f32>(1.,-3.1,6.99)"),
3994
            (log, "log", "vec3<f32>(1.,-3.1,6.99)"),
3995
            (log2, "log2", "vec3<f32>(1.,-3.1,6.99)"),
3996
            (norm, "normalize", "vec3<f32>(1.,-3.1,6.99)"),
3997
            (pack4x8snorm, "pack4x8snorm", "vec4<f32>(-1.,1.,0.,7.2)"),
3998
            (pack4x8unorm, "pack4x8unorm", "vec4<f32>(-1.,1.,0.,7.2)"),
3999
            (saturate, "saturate", "vec3<f32>(1.,-3.1,6.99)"),
4000
            (sign, "sign", "vec3<f32>(1.,-3.1,6.99)"),
4001
            (sin, "sin", "vec3<f32>(1.,-3.1,6.99)"),
4002
            (sqrt, "sqrt", "vec3<f32>(1.,-3.1,6.99)"),
4003
            (tan, "tan", "vec3<f32>(1.,-3.1,6.99)"),
4004
            (unpack4x8snorm, "unpack4x8snorm", "0u"),
4005
            (unpack4x8unorm, "unpack4x8unorm", "0u"),
4006
        ] {
4007
            let expr = ctx.eval(&m, expr);
4008
            assert!(expr.is_ok());
4009
            let expr = expr.unwrap();
4010
            assert_eq!(expr, format!("{}({})", op, inner));
4011
        }
4012

4013
        for (expr, op, inner) in [
4014
            (comp_x, "x", "vec4<f32>(0.,0.,0.,1.)"),
4015
            (comp_y, "y", "vec4<f32>(0.,0.,0.,1.)"),
4016
            (comp_z, "z", "vec4<f32>(0.,0.,0.,1.)"),
4017
            (comp_w, "w", "vec4<f32>(0.,0.,0.,1.)"),
4018
        ] {
4019
            let expr = ctx.eval(&m, expr);
4020
            assert!(expr.is_ok());
4021
            let expr = expr.unwrap();
4022
            assert_eq!(expr, format!("{}.{}", inner, op));
4023
        }
4024
    }
4025

4026
    #[test]
4027
    fn binary_expr() {
4028
        let mut m = Module::default();
4029

4030
        let x = m.attr(Attribute::POSITION);
4031
        let y = m.lit(Vec3::ONE);
4032

4033
        let cross = m.cross(x, y);
4034
        let dist = m.distance(x, y);
4035
        let dot = m.dot(x, y);
4036
        let min = m.min(x, y);
4037
        let max = m.max(x, y);
4038
        let step = m.step(x, y);
4039

4040
        let property_layout = PropertyLayout::default();
4041
        let particle_layout = ParticleLayout::default();
4042
        let mut ctx =
4043
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4044

4045
        for (expr, op) in [
4046
            (cross, "cross"),
4047
            (dist, "distance"),
4048
            (dot, "dot"),
4049
            (min, "min"),
4050
            (max, "max"),
4051
            (step, "step"),
4052
        ] {
4053
            let expr = ctx.eval(&m, expr);
4054
            assert!(expr.is_ok());
4055
            let expr = expr.unwrap();
4056
            assert_eq!(
4057
                expr,
4058
                format!(
4059
                    "{}(particle.{}, vec3<f32>(1.,1.,1.))",
4060
                    op,
4061
                    Attribute::POSITION.name(),
4062
                )
4063
            );
4064
        }
4065
    }
4066

4067
    #[test]
4068
    fn ternary_expr() {
4069
        let mut m = Module::default();
4070

4071
        let x = m.attr(Attribute::POSITION);
4072
        let y = m.lit(Vec3::ONE);
4073
        let t = m.lit(0.3);
4074

4075
        let mix = m.mix(x, y, t);
4076
        let smoothstep = m.smoothstep(x, y, x);
4077

4078
        let property_layout = PropertyLayout::default();
4079
        let particle_layout = ParticleLayout::default();
4080
        let mut ctx =
4081
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4082

4083
        for (expr, op, third) in [(mix, "mix", t), (smoothstep, "smoothstep", x)] {
4084
            let expr = ctx.eval(&m, expr);
4085
            assert!(expr.is_ok());
4086
            let expr = expr.unwrap();
4087
            let third = ctx.eval(&m, third).unwrap();
4088
            assert_eq!(
4089
                expr,
4090
                format!(
4091
                    "{}(particle.{}, vec3<f32>(1.,1.,1.), {})",
4092
                    op,
4093
                    Attribute::POSITION.name(),
4094
                    third
4095
                )
4096
            );
4097
        }
4098
    }
4099

4100
    #[test]
4101
    fn cast_expr() {
4102
        let mut m = Module::default();
4103

4104
        let x = m.attr(Attribute::POSITION);
4105
        let y = m.lit(IVec2::ONE);
4106
        let z = m.lit(0.3);
4107
        let w = m.lit(false);
4108

4109
        let cx = m.cast(x, VectorType::VEC3I);
4110
        let cy = m.cast(y, VectorType::VEC2U);
4111
        let cz = m.cast(z, ScalarType::Int);
4112
        let cw = m.cast(w, ScalarType::Uint);
4113

4114
        let property_layout = PropertyLayout::default();
4115
        let particle_layout = ParticleLayout::default();
4116
        let mut ctx =
4117
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4118

4119
        for (expr, cast, target) in [
4120
            (x, cx, ValueType::Vector(VectorType::VEC3I)),
4121
            (y, cy, VectorType::VEC2U.into()),
4122
            (z, cz, ScalarType::Int.into()),
4123
            (w, cw, ScalarType::Uint.into()),
4124
        ] {
4125
            let expr = ctx.eval(&m, expr);
4126
            assert!(expr.is_ok());
4127
            let expr = expr.unwrap();
4128
            let cast = ctx.eval(&m, cast);
4129
            assert!(cast.is_ok());
4130
            let cast = cast.unwrap();
4131
            assert_eq!(cast, format!("{}({})", target.to_wgsl_string(), expr));
4132
        }
4133
    }
4134

4135
    #[test]
4136
    fn attribute_pointer() {
4137
        let mut m = Module::default();
4138
        let x = m.attr(Attribute::POSITION);
4139

4140
        let property_layout = PropertyLayout::default();
4141
        let particle_layout = ParticleLayout::default();
4142
        let mut ctx =
4143
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4144

4145
        let res = ctx.eval(&m, x);
4146
        assert!(res.is_ok());
4147
        let xx = res.ok().unwrap();
4148
        assert_eq!(xx, format!("particle.{}", Attribute::POSITION.name()));
4149

4150
        // Use a different context; it's invalid to reuse a mutated context, as the
4151
        // expression cache will have been generated with the wrong context.
4152
        let mut ctx =
4153
            ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout)
4154
                .with_attribute_pointer();
4155

4156
        let res = ctx.eval(&m, x);
4157
        assert!(res.is_ok());
4158
        let xx = res.ok().unwrap();
4159
        assert_eq!(xx, format!("(*particle).{}", Attribute::POSITION.name()));
4160
    }
4161

4162
    #[test]
4163
    #[should_panic]
4164
    fn invalid_cast_vector_to_scalar() {
4165
        let mut m = Module::default();
4166
        let x = m.lit(Vec2::ONE);
4167
        let _ = m.cast(x, ScalarType::Float);
4168
    }
4169

4170
    #[test]
4171
    #[should_panic]
4172
    fn invalid_cast_matrix_to_scalar() {
4173
        let mut m = Module::default();
4174
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4175
        let _ = m.cast(x, ScalarType::Float);
4176
    }
4177

4178
    #[test]
4179
    #[should_panic]
4180
    fn invalid_cast_matrix_to_vector() {
4181
        let mut m = Module::default();
4182
        let x = m.lit(Value::Matrix(Mat4::ZERO.into()));
4183
        let _ = m.cast(x, VectorType::VEC4F);
4184
    }
4185

4186
    #[test]
4187
    #[should_panic]
4188
    fn invalid_cast_scalar_to_matrix() {
4189
        let mut m = Module::default();
4190
        let x = m.lit(3.);
4191
        let _ = m.cast(x, MatrixType::MAT3X3F);
4192
    }
4193

4194
    #[test]
4195
    #[should_panic]
4196
    fn invalid_cast_vector_to_matrix() {
4197
        let mut m = Module::default();
4198
        let x = m.lit(Vec3::ZERO);
4199
        let _ = m.cast(x, MatrixType::MAT2X4F);
4200
    }
4201

4202
    #[test]
4203
    fn cast_expr_new() {
4204
        let mut m = Module::default();
4205

4206
        let x = m.attr(Attribute::POSITION);
4207
        let c = CastExpr::new(x, VectorType::VEC3F);
4208
        assert_eq!(c.value_type(), ValueType::Vector(VectorType::VEC3F));
4209
        assert_eq!(c.is_valid(&m), Some(true));
4210

4211
        let x = m.attr(Attribute::POSITION);
4212
        let c = CastExpr::new(x, ScalarType::Bool);
4213
        assert_eq!(c.value_type(), ValueType::Scalar(ScalarType::Bool));
4214
        assert_eq!(c.is_valid(&m), Some(false)); // invalid cast vector -> scalar
4215

4216
        let p = m.add_property("my_prop", 3.0.into());
4217
        let y = m.prop(p);
4218
        let c = CastExpr::new(y, MatrixType::MAT2X3F);
4219
        assert_eq!(c.value_type(), ValueType::Matrix(MatrixType::MAT2X3F));
4220
        assert_eq!(c.is_valid(&m), None); // properties' value_type() is unknown
4221
    }
4222

4223
    #[test]
4224
    fn side_effect() {
4225
        let mut m = Module::default();
4226

4227
        // Adding the same cloned expression with side effect to itself should yield
4228
        // twice the value, and not two separate evaluations of the expression.
4229
        // CORRECT:
4230
        //   let r = frand();
4231
        //   r + r
4232
        // INCORRECT:
4233
        //   frand() + frand()
4234

4235
        let r = m.builtin(BuiltInOperator::Rand(ScalarType::Float.into()));
4236
        let r2 = r;
4237
        let r3 = r2;
4238
        let a = m.add(r, r2);
4239
        let b = m.mix(r, r2, r3);
4240
        let c = m.abs(a);
4241

4242
        {
4243
            let property_layout = PropertyLayout::default();
4244
            let particle_layout = ParticleLayout::default();
4245
            let mut ctx =
4246
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4247
            let value = ctx.eval(&m, a).unwrap();
4248
            assert_eq!(value, "(var0) + (var0)");
4249
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4250
        }
4251

4252
        {
4253
            let property_layout = PropertyLayout::default();
4254
            let particle_layout = ParticleLayout::default();
4255
            let mut ctx =
4256
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4257
            let value = ctx.eval(&m, b).unwrap();
4258
            assert_eq!(value, "mix(var0, var0, var0)");
4259
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4260
        }
4261

4262
        {
4263
            let property_layout = PropertyLayout::default();
4264
            let particle_layout = ParticleLayout::default();
4265
            let mut ctx =
4266
                ShaderWriter::new(ModifierContext::Update, &property_layout, &particle_layout);
4267
            let value = ctx.eval(&m, c).unwrap();
4268
            assert_eq!(value, "abs((var0) + (var0))");
4269
            assert_eq!(ctx.main_code, "let var0 = frand();\n");
4270
        }
4271
    }
4272

4273
    // #[test]
4274
    // fn serde() {
4275
    //     let v = Value::Scalar(3.0_f32.into());
4276
    //     let l: LiteralExpr = v.into();
4277
    //     assert_eq!(Ok(v), l.eval());
4278
    //     let s = ron::to_string(&l).unwrap();
4279
    //     println!("literal: {:?}", s);
4280
    //     let l_serde: LiteralExpr = ron::from_str(&s).unwrap();
4281
    //     assert_eq!(l_serde, l);
4282

4283
    //     let b: ExprHandle = Box::new(l);
4284
    //     let s = ron::to_string(&b).unwrap();
4285
    //     println!("boxed literal: {:?}", s);
4286
    //     let b_serde: ExprHandle = ron::from_str(&s).unwrap();
4287
    //     assert!(b_serde.is_const());
4288
    //     assert_eq!(b_serde.to_wgsl_string(), b.to_wgsl_string());
4289

4290
    //     let v0 = Value::Scalar(3.0_f32.into());
4291
    //     let v1 = Value::Scalar(2.5_f32.into());
4292
    //     let l0: LiteralExpr = v0.into();
4293
    //     let l1: LiteralExpr = v1.into();
4294
    //     let a = l0 + l1;
4295
    //     assert!(a.is_const());
4296
    //     assert_eq!(Ok(Value::Scalar(5.5_f32.into())), a.eval());
4297
    //     let s = ron::to_string(&a).unwrap();
4298
    //     println!("add: {:?}", s);
4299
    //     let a_serde: AddExpr = ron::from_str(&s).unwrap();
4300
    //     println!("a_serde: {:?}", a_serde);
4301
    //     assert_eq!(a_serde.left.to_wgsl_string(), l0.to_wgsl_string());
4302
    //     assert_eq!(a_serde.right.to_wgsl_string(), l1.to_wgsl_string());
4303
    // }
4304
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc