1 /**
2     Particle filter
3 
4     Copyright: (c) Enalye 2017
5     License: Zlib
6     Authors: Enalye
7 */
8 
9 module atelier.core.particlefilter;
10 
11 import std.typecons;
12 import std.conv: to;
13 
14 import atelier.core.util;
15 import atelier.core.vec2;
16 import atelier.core.color;
17 import atelier.core.stream;
18 import atelier.core.particle;
19 /+
20 class ParticleFilter {
21 	protected {
22 		Vec2f _position = Vec2f.zero;
23 		Vec2f _size = Vec2f.one * 100f;
24 		int _id = -1;
25 		uint _nbProperties = 0U;
26 		bool _isCircle = false;
27 	}
28 
29 	@property {
30 		int id() { return _id; }
31 
32 		Vec2f position() const { return _position; }
33 		Vec2f position(Vec2f newPosition) { return _position = newPosition; }
34 	}
35 
36 	bool isInside(const Vec2f pos) const {
37 		if(_isCircle)
38 			return _position.distanceSquared(pos) < _size.x * _size.x;
39 		else
40 			return pos.isBetween(_position - _size / 2f, _position + _size / 2f);
41 	}
42 
43 	void apply(Particle particle, float deltaTime) {
44 		if(isInside(particle.position))
45 			updateParticle(particle, deltaTime);
46 	}
47 
48 	protected abstract void updateParticle(Particle particle, float deltaTime);
49 
50 	alias FilterProperty = Tuple!(string, float, float, uint);
51 	abstract FilterProperty[] getProperties() const;
52 	abstract float property(uint id) const;
53 	abstract void property(uint id, float newValue);
54 
55 	alias FilterDisplay = Tuple!(string, const bool, const Vec2f, bool, const Vec2f, const Color);
56 	abstract FilterDisplay getDisplay() const;
57 
58 	void save(OutStream stream) const {
59 		stream.write!float(_position.x);
60 		stream.write!float(_position.y);
61 		foreach(uint id; 0.._nbProperties)
62 			stream.write!float(property(id));
63 	}
64 
65 	void load(InStream stream) {
66 		_position = Vec2f(stream.read!float(), stream.read!float());
67 		foreach(uint id; 0.._nbProperties)
68 			property(id, stream.read!float());
69 	}
70 }
71 
72 //Force Filter
73 final class ForceFilterCircle: ParticleFilter {
74 	private	{
75 		float _angle = 0f, _acceleration = 0f;
76 		Vec2f _force = Vec2f.zero;
77 	}
78 
79 	this() {
80 		_id = 0;
81 		_nbProperties = 3U;
82 		_isCircle = true;
83 	}
84 
85 	override float property(uint id) const {
86 		switch(id) {
87 		case 0:
88 			return _size.x;
89 		case 1:
90 			return _angle;
91 		case 2:
92 			return _acceleration;
93 		default:
94 			throw new Exception("Filter property out of range");
95 		}
96 	}
97 
98 	override void property(uint id, float newValue) {
99 		switch(id) {
100 		case 0:
101 			_size.x = newValue;
102 			_size.y = newValue;
103 			break;
104 		case 1:
105 			_angle = newValue;
106 			_force = Vec2f.angled(_angle) * _acceleration;
107 			break;
108 		case 2:
109 			_acceleration = newValue;
110 			_force = Vec2f.angled(_angle) * _acceleration;
111 			break;
112 		default:
113 			throw new Exception("Filter property out of range");
114 		}
115 	}
116 
117 	protected override void updateParticle(Particle particle, float deltaTime) {
118 		particle.velocity += _force * deltaTime;
119 	}
120 
121 	override FilterProperty[] getProperties() const {
122 		return [
123 			tuple("Rayon", 1f, 1000f, 999u),
124 			tuple("Angle", 0f, 360f, 360u),
125 			tuple("Accel.", 0f, 0.5f, 1000u)
126 			];
127 	}
128 
129 	override FilterDisplay getDisplay() const {
130 		return tuple("Force", _isCircle, _size, true, cast(const Vec2f)(_force * 1000f), Color.red);
131 	}
132 }
133 
134 final class ForceFilterRect: ParticleFilter {
135 	private	{
136 		float _angle = 0f, _acceleration = 0f;
137 		Vec2f _force = Vec2f.zero;
138 	}
139 
140 	this() {
141 		_id = 1;
142 		_nbProperties = 4U;
143 		_isCircle = false;
144 	}
145 
146 	override float property(uint id) const {
147 		switch(id) {
148 		case 0:
149 			return _size.x;
150 		case 1:
151 			return _size.y;
152 		case 2:
153 			return _angle;
154 		case 3:
155 			return _acceleration;
156 		default:
157 			throw new Exception("Filter property out of range");
158 		}
159 	}
160 
161 	override void property(uint id, float newValue) {
162 		switch(id) {
163 		case 0:
164 			_size.x = newValue;
165 			break;
166 		case 1:
167 			_size.y = newValue;
168 			break;
169 		case 2:
170 			_angle = newValue;
171 			_force = Vec2f.angled(_angle) * _acceleration;
172 			break;
173 		case 3:
174 			_acceleration = newValue;
175 			_force = Vec2f.angled(_angle) * _acceleration;
176 			break;
177 		default:
178 			throw new Exception("Filter property out of range");
179 		}
180 	}
181 
182 	protected override void updateParticle(Particle particle, float deltaTime) {
183 		particle.velocity += _force * deltaTime;
184 	}
185 
186 	override FilterProperty[] getProperties() const {
187 		return [
188 			tuple("Longueur", 2f, 2000f, 1998u),
189 			tuple("Hauteur", 2f, 2000f, 1998u),
190 			tuple("Angle", 0f, 360f, 360u),
191 			tuple("Accel.", 0f, 0.5f, 1000u)
192 			];
193 	}
194 
195 	override FilterDisplay getDisplay() const {
196 		return tuple("Force", _isCircle, _size, true, cast(const Vec2f)(_force * 1000f), Color.red);
197 	}
198 }
199 
200 //SetSpeed Filter
201 final class SetSpeedFilterCircle: ParticleFilter {
202 	private	{
203 		float _speed = 0f; 
204 	}
205 
206 	this() {
207 		_id = 2;
208 		_nbProperties = 2U;
209 		_isCircle = true;
210 	}
211 
212 	override float property(uint id) const {
213 		switch(id) {
214 		case 0:
215 			return _size.x;
216 		case 1:
217 			return _speed;
218 		default:
219 			throw new Exception("Filter property out of range");
220 		}
221 	}
222 
223 	override void property(uint id, float newValue) {
224 		switch(id) {
225 		case 0:
226 			_size.x = newValue;
227 			_size.y = newValue;
228 			break;
229 		case 1:
230 			_speed = newValue;
231 			break;
232 		default:
233 			throw new Exception("Filter property out of range");
234 		}
235 	}
236 
237 	protected override void updateParticle(Particle particle, float deltaTime) {
238 		particle.velocity = particle.velocity.normalized * _speed;
239 	}
240 
241 	override FilterProperty[] getProperties() const {
242 		return [
243 			tuple("Rayon", 1f, 1000f, 999u),
244 			tuple("Vitesse", 0f, 10f, 200u)
245 			];
246 	}
247 
248 	override FilterDisplay getDisplay() const {
249 		return tuple("Vitesse: " ~ to!string(_speed), _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.green);
250 	}
251 }
252 
253 final class SetSpeedFilterRect: ParticleFilter {
254 	private	{
255 		float _speed = 0f; 
256 	}
257 
258 	this() {
259 		_id = 3;
260 		_nbProperties = 3U;
261 		_isCircle = false;
262 	}
263 
264 	override float property(uint id) const {
265 		switch(id) {
266 		case 0:
267 			return _size.x;
268 		case 1:
269 			return _size.y;
270 		case 2:
271 			return _speed;
272 		default:
273 			throw new Exception("Filter property out of range");
274 		}
275 	}
276 
277 	override void property(uint id, float newValue) {
278 		switch(id) {
279 		case 0:
280 			_size.x = newValue;
281 			break;
282 		case 1:
283 			_size.y = newValue;
284 			break;
285 		case 2:
286 			_speed = newValue;
287 			break;
288 		default:
289 			throw new Exception("Filter property out of range");
290 		}
291 	}
292 
293 	protected override void updateParticle(Particle particle, float deltaTime) {
294 		particle.velocity = particle.velocity.normalized * _speed;
295 	}
296 
297 	override FilterProperty[] getProperties() const {
298 		return [
299 			tuple("Longueur", 2f, 2000f, 1998u),
300 			tuple("Hauteur", 2f, 2000f, 1998u),
301 			tuple("Vitesse", 0f, 10f, 200u)
302 			];
303 	}
304 
305 	override FilterDisplay getDisplay() const {
306 		return tuple("Vitesse: " ~ to!string(_speed), _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.green);
307 	}
308 }
309 
310 //SpeedLimit Filter
311 final class SpeedLimitFilterCircle: ParticleFilter {
312 	private	{
313 		float _limit = 0f; 
314 	}
315 
316 	this() {
317 		_id = 4;
318 		_nbProperties = 2U;
319 		_isCircle = true;
320 	}
321 
322 	override float property(uint id) const {
323 		switch(id) {
324 		case 0:
325 			return _size.x;
326 		case 1:
327 			return _limit;
328 		default:
329 			throw new Exception("Filter property out of range");
330 		}
331 	}
332 
333 	override void property(uint id, float newValue) {
334 		switch(id) {
335 		case 0:
336 			_size.x = newValue;
337 			_size.y = newValue;
338 			break;
339 		case 1:
340 			_limit = newValue;
341 			break;
342 		default:
343 			throw new Exception("Filter property out of range");
344 		}
345 	}
346 
347 	protected override void updateParticle(Particle particle, float deltaTime) {
348 		if(particle.velocity.lengthSquared > _limit * _limit)
349 			particle.velocity = particle.velocity.normalized * _limit;
350 	}
351 
352 	override FilterProperty[] getProperties() const {
353 		return [
354 			tuple("Rayon", 1f, 1000f, 999u),
355 			tuple("Limite", 0f, 10f, 200u)
356 			];
357 	}
358 
359 	override FilterDisplay getDisplay() const {
360 		return tuple("Vit. Limite: " ~ to!string(_limit), _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.green);
361 	}
362 }
363 
364 final class SpeedLimitFilterRect: ParticleFilter {
365 	private	{
366 		float _limit = 0f; 
367 	}
368 
369 	this() {
370 		_id = 5;
371 		_nbProperties = 3U;
372 		_isCircle = false;
373 	}
374 
375 	override float property(uint id) const {
376 		switch(id) {
377 		case 0:
378 			return _size.x;
379 		case 1:
380 			return _size.y;
381 		case 2:
382 			return _limit;
383 		default:
384 			throw new Exception("Filter property out of range");
385 		}
386 	}
387 
388 	override void property(uint id, float newValue) {
389 		switch(id) {
390 		case 0:
391 			_size.x = newValue;
392 			break;
393 		case 1:
394 			_size.y = newValue;
395 			break;
396 		case 2:
397 			_limit = newValue;
398 			break;
399 		default:
400 			throw new Exception("Filter property out of range");
401 		}
402 	}
403 
404 	protected override void updateParticle(Particle particle, float deltaTime) {
405 		if(particle.velocity.lengthSquared > _limit * _limit)
406 			particle.velocity = particle.velocity.normalized * _limit;
407 	}
408 
409 	override FilterProperty[] getProperties() const {
410 		return [
411 			tuple("Longueur", 2f, 2000f, 1998u),
412 			tuple("Hauteur", 2f, 2000f, 1998u),
413 			tuple("Limite", 0f, 10f, 200u)
414 			];
415 	}
416 
417 	override FilterDisplay getDisplay() const {
418 		return tuple("Vit. Limite: " ~ to!string(_limit), _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.green);
419 	}
420 }
421 
422 //Attract Filter
423 final class AttractFilterCircle: ParticleFilter {
424 	private	{
425 		float _acceleration = 0f;
426 	}
427 
428 	this() {
429 		_id = 6;
430 		_nbProperties = 2U;
431 		_isCircle = true;
432 	}
433 
434 	override float property(uint id) const {
435 		switch(id) {
436 		case 0:
437 			return _size.x;
438 		case 1:
439 			return _acceleration;
440 		default:
441 			throw new Exception("Filter property out of range");
442 		}
443 	}
444 
445 	override void property(uint id, float newValue) {
446 		switch(id) {
447 		case 0:
448 			_size.x = newValue;
449 			_size.y = newValue;
450 			break;
451 		case 1:
452 			_acceleration = newValue;
453 			break;
454 		default:
455 			throw new Exception("Filter property out of range");
456 		}
457 	}
458 
459 	protected override void updateParticle(Particle particle, float deltaTime) {
460 		particle.velocity += (_position - particle.position).normalized * _acceleration * deltaTime;
461 	}
462 
463 	override FilterProperty[] getProperties() const {
464 		return [
465 			tuple("Rayon", 1f, 1000f, 999u),
466 			tuple("Accel.", 0f, 0.5f, 1000u)
467 			];
468 	}
469 
470 	override FilterDisplay getDisplay() const {
471 		return tuple("Attracteur", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.blue);
472 	}
473 }
474 
475 final class AttractFilterRect: ParticleFilter {
476 	private	{
477 		float _acceleration = 0f;
478 	}
479 
480 	this() {
481 		_id = 7;
482 		_nbProperties = 3U;
483 		_isCircle = false;
484 	}
485 
486 	override float property(uint id) const {
487 		switch(id) {
488 		case 0:
489 			return _size.x;
490 		case 1:
491 			return _size.y;
492 		case 2:
493 			return _acceleration;
494 		default:
495 			throw new Exception("Filter property out of range");
496 		}
497 	}
498 
499 	override void property(uint id, float newValue) {
500 		switch(id) {
501 		case 0:
502 			_size.x = newValue;
503 			break;
504 		case 1:
505 			_size.y = newValue;
506 			break;
507 		case 2:
508 			_acceleration = newValue;
509 			break;
510 		default:
511 			throw new Exception("Filter property out of range");
512 		}
513 	}
514 
515 	protected override void updateParticle(Particle particle, float deltaTime) {
516 		particle.velocity += (_position - particle.position).normalized * _acceleration * deltaTime;
517 	}
518 
519 	override FilterProperty[] getProperties() const {
520 		return [
521 			tuple("Longueur", 2f, 2000f, 1998u),
522 			tuple("Hauteur", 2f, 2000f, 1998u),
523 			tuple("Accel.", 0f, 0.5f, 1000u)
524 			];
525 	}
526 
527 	override FilterDisplay getDisplay() const {
528 		return tuple("Attracteur", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.blue);
529 	}
530 }
531 
532 //Repulse Filter
533 final class RepulseFilterCircle: ParticleFilter {
534 	private	{
535 		float _acceleration = 0f;
536 	}
537 
538 	this() {
539 		_id = 8;
540 		_nbProperties = 2U;
541 		_isCircle = true;
542 	}
543 
544 	override float property(uint id) const {
545 		switch(id) {
546 		case 0:
547 			return _size.x;
548 		case 1:
549 			return _acceleration;
550 		default:
551 			throw new Exception("Filter property out of range");
552 		}
553 	}
554 
555 	override void property(uint id, float newValue) {
556 		switch(id) {
557 		case 0:
558 			_size.x = newValue;
559 			_size.y = newValue;
560 			break;
561 		case 1:
562 			_acceleration = newValue;
563 			break;
564 		default:
565 			throw new Exception("Filter property out of range");
566 		}
567 	}
568 
569 	protected override void updateParticle(Particle particle, float deltaTime) {
570 		particle.velocity += (particle.position - _position).normalized * _acceleration * deltaTime;
571 	}
572 
573 	override FilterProperty[] getProperties() const {
574 		return [
575 			tuple("Rayon", 1f, 1000f, 999u),
576 			tuple("Accel.", 0f, 0.5f, 1000u)
577 			];
578 	}
579 
580 	override FilterDisplay getDisplay() const {
581 		return tuple("Répulseur", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.cyan);
582 	}
583 }
584 
585 final class RepulseFilterRect: ParticleFilter {
586 	private	{
587 		float _acceleration = 0f;
588 	}
589 
590 	this() {
591 		_id = 9;
592 		_nbProperties = 3U;
593 		_isCircle = false;
594 	}
595 
596 	override float property(uint id) const {
597 		switch(id) {
598 		case 0:
599 			return _size.x;
600 		case 1:
601 			return _size.y;
602 		case 2:
603 			return _acceleration;
604 		default:
605 			throw new Exception("Filter property out of range");
606 		}
607 	}
608 
609 	override void property(uint id, float newValue) {
610 		switch(id) {
611 		case 0:
612 			_size.x = newValue;
613 			break;
614 		case 1:
615 			_size.y = newValue;
616 			break;
617 		case 2:
618 			_acceleration = newValue;
619 			break;
620 		default:
621 			throw new Exception("Filter property out of range");
622 		}
623 	}
624 
625 	protected override void updateParticle(Particle particle, float deltaTime) {
626 		particle.velocity += (particle.position - _position).normalized * _acceleration * deltaTime;
627 	}
628 
629 	override FilterProperty[] getProperties() const {
630 		return [
631 			tuple("Longueur", 2f, 2000f, 1998u),
632 			tuple("Hauteur", 2f, 2000f, 1998u),
633 			tuple("Accel.", 0f, 0.5f, 1000u)
634 			];
635 	}
636 
637 	override FilterDisplay getDisplay() const {
638 		return tuple("Répulseur", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.cyan);
639 	}
640 }
641 
642 //Destructor Filter
643 final class DestructorFilterCircle: ParticleFilter {
644 	this() {
645 		_id = 10;
646 		_nbProperties = 1U;
647 		_isCircle = true;
648 	}
649 
650 	override float property(uint id) const {
651 		switch(id) {
652 		case 0:
653 			return _size.x;
654 		default:
655 			throw new Exception("Filter property out of range");
656 		}
657 	}
658 
659 	override void property(uint id, float newValue) {
660 		switch(id) {
661 		case 0:
662 			_size.x = newValue;
663 			_size.y = newValue;
664 			break;
665 		default:
666 			throw new Exception("Filter property out of range");
667 		}
668 	}
669 
670 	protected override void updateParticle(Particle particle, float deltaTime) {
671 		particle.timeToLive = 0f;
672 	}
673 
674 	override FilterProperty[] getProperties() const {
675 		return [
676 			tuple("Rayon", 1f, 1000f, 999u)
677 			];
678 	}
679 
680 	override FilterDisplay getDisplay() const {
681 		return tuple("Destructeur", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.silver);
682 	}
683 }
684 
685 final class DestructorFilterRect: ParticleFilter {
686 	this() {
687 		_id = 11;
688 		_nbProperties = 2U;
689 		_isCircle = false;
690 	}
691 
692 	override float property(uint id) const {
693 		switch(id) {
694 		case 0:
695 			return _size.x;
696 		case 1:
697 			return _size.y;
698 		default:
699 			throw new Exception("Filter property out of range");
700 		}
701 	}
702 
703 	override void property(uint id, float newValue) {
704 		switch(id) {
705 		case 0:
706 			_size.x = newValue;
707 			break;
708 		case 1:
709 			_size.y = newValue;
710 			break;
711 		default:
712 			throw new Exception("Filter property out of range");
713 		}
714 	}
715 
716 	protected override void updateParticle(Particle particle, float deltaTime) {
717 		particle.timeToLive = 0f;
718 	}
719 
720 	override FilterProperty[] getProperties() const {
721 		return [
722 			tuple("Longueur", 2f, 2000f, 1998u),
723 			tuple("Hauteur", 2f, 2000f, 1998u)
724 			];
725 	}
726 
727 	override FilterDisplay getDisplay() const {
728 		return tuple("Destructeur", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.silver);
729 	}
730 }
731 
732 //SetScale Filter
733 final class SetScaleFilterCircle: ParticleFilter {
734 	private	float _scale = 1f;
735 
736 	this() {
737 		_id = 12;
738 		_nbProperties = 2U;
739 		_isCircle = true;
740 	}
741 
742 	override float property(uint id) const {
743 		switch(id) {
744 		case 0:
745 			return _size.x;
746 		case 1:
747 			return _scale;
748 		default:
749 			throw new Exception("Filter property out of range");
750 		}
751 	}
752 
753 	override void property(uint id, float newValue) {
754 		switch(id) {
755 		case 0:
756 			_size.x = newValue;
757 			_size.y = newValue;
758 			break;
759 		case 1:
760 			_scale = newValue;
761 			break;
762 		default:
763 			throw new Exception("Filter property out of range");
764 		}
765 	}
766 
767 	protected override void updateParticle(Particle particle, float deltaTime) {
768 		particle.scale = _scale;
769 	}
770 
771 	override FilterProperty[] getProperties() const {
772 		return [
773 			tuple("Rayon", 1f, 1000f, 999u),
774 			tuple("Taille", 0f, 10f, 1000u)
775 			];
776 	}
777 
778 	override FilterDisplay getDisplay() const {
779 		return tuple("Taille", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.olive);
780 	}
781 }
782 
783 final class SetScaleFilterRect: ParticleFilter {
784 	private	float _scale = 1f;
785 
786 	this() {
787 		_id = 13;
788 		_nbProperties = 3U;
789 		_isCircle = false;
790 	}
791 
792 	override float property(uint id) const {
793 		switch(id) {
794 		case 0:
795 			return _size.x;
796 		case 1:
797 			return _size.y;
798 		case 2:
799 			return _scale;
800 		default:
801 			throw new Exception("Filter property out of range");
802 		}
803 	}
804 
805 	override void property(uint id, float newValue) {
806 		switch(id) {
807 		case 0:
808 			_size.x = newValue;
809 			break;
810 		case 1:
811 			_size.y = newValue;
812 			break;
813 		case 2:
814 			_scale = newValue;
815 			break;
816 		default:
817 			throw new Exception("Filter property out of range");
818 		}
819 	}
820 
821 	protected override void updateParticle(Particle particle, float deltaTime) {
822 		particle.scale = _scale;
823 	}
824 
825 	override FilterProperty[] getProperties() const {
826 		return [
827 			tuple("Longueur", 2f, 2000f, 1998u),
828 			tuple("Hauteur", 2f, 2000f, 1998u),
829 			tuple("Taille", 0f, 10f, 1000u)
830 			];
831 	}
832 
833 	override FilterDisplay getDisplay() const {
834 		return tuple("Taille", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.olive);
835 	}
836 }
837 
838 //MixScale Filter
839 final class MixScaleFilterCircle: ParticleFilter {
840 	private	{
841 		float _scale = 1f, _blend = 1f;
842 	}
843 
844 	this() {
845 		_id = 14;
846 		_nbProperties = 3U;
847 		_isCircle = true;
848 	}
849 
850 	override float property(uint id) const {
851 		switch(id) {
852 		case 0:
853 			return _size.x;
854 		case 1:
855 			return _scale;
856 		case 2:
857 			return _blend;
858 		default:
859 			throw new Exception("Filter property out of range");
860 		}
861 	}
862 
863 	override void property(uint id, float newValue) {
864 		switch(id) {
865 		case 0:
866 			_size.x = newValue;
867 			_size.y = newValue;
868 			break;
869 		case 1:
870 			_scale = newValue;
871 			break;
872 		case 2:
873 			_blend = newValue;
874 			break;
875 		default:
876 			throw new Exception("Filter property out of range");
877 		}
878 	}
879 
880 	protected override void updateParticle(Particle particle, float deltaTime) {
881 		particle.scale = lerp(particle.scale, _scale, _blend * deltaTime);
882 	}
883 
884 	override FilterProperty[] getProperties() const {
885 		return [
886 			tuple("Rayon", 1f, 1000f, 999u),
887 			tuple("Taille", 0f, 10f, 1000u),
888 			tuple("Mélange", 0.0001f, 0.1f, 1000u)
889 			];
890 	}
891 
892 	override FilterDisplay getDisplay() const {
893 		return tuple("M.Taille", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.navy);
894 	}
895 }
896 
897 final class MixScaleFilterRect: ParticleFilter {
898 	private	{
899 		float _scale = 1f, _blend = 1f;
900 	}
901 
902 	this() {
903 		_id = 15;
904 		_nbProperties = 4U;
905 		_isCircle = false;
906 	}
907 
908 	override float property(uint id) const {
909 		switch(id) {
910 		case 0:
911 			return _size.x;
912 		case 1:
913 			return _size.y;
914 		case 2:
915 			return _scale;
916 		case 3:
917 			return _blend;
918 		default:
919 			throw new Exception("Filter property out of range");
920 		}
921 	}
922 
923 	override void property(uint id, float newValue) {
924 		switch(id) {
925 		case 0:
926 			_size.x = newValue;
927 			break;
928 		case 1:
929 			_size.y = newValue;
930 			break;
931 		case 2:
932 			_scale = newValue;
933 			break;
934 		case 3:
935 			_blend = newValue;
936 			break;
937 		default:
938 			throw new Exception("Filter property out of range");
939 		}
940 	}
941 
942 	protected override void updateParticle(Particle particle, float deltaTime) {
943 		particle.scale = lerp(particle.scale, _scale, _blend * deltaTime);
944 	}
945 
946 	override FilterProperty[] getProperties() const {
947 		return [
948 			tuple("Longueur", 2f, 2000f, 1998u),
949 			tuple("Hauteur", 2f, 2000f, 1998u),
950 			tuple("Taille", 0f, 10f, 1000u),
951 			tuple("Mélange", 0.0001f, 0.1f, 1000u)
952 			];
953 	}
954 
955 	override FilterDisplay getDisplay() const {
956 		return tuple("M.Taille", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, Color.navy);
957 	}
958 }
959 
960 //SetColor Filter
961 final class SetColorFilterCircle: ParticleFilter {
962 	private	Color _color;
963 
964 	this() {
965 		_id = 16;
966 		_nbProperties = 5U;
967 		_isCircle = true;
968 	}
969 
970 	override float property(uint id) const {
971 		switch(id) {
972 		case 0:
973 			return _size.x;
974 		case 1:
975 			return _color.r;
976 		case 2:
977 			return _color.g;
978 		case 3:
979 			return _color.b;
980 		case 4:
981 			return _color.a;
982 		default:
983 			throw new Exception("Filter property out of range");
984 		}
985 	}
986 
987 	override void property(uint id, float newValue) {
988 		switch(id) {
989 		case 0:
990 			_size.x = newValue;
991 			_size.y = newValue;
992 			break;
993 		case 1:
994 			_color.r = newValue;
995 			break;
996 		case 2:
997 			_color.g = newValue;
998 			break;
999 		case 3:
1000 			_color.b = newValue;
1001 			break;
1002 		case 4:
1003 			_color.a = newValue;
1004 			break;
1005 		default:
1006 			throw new Exception("Filter property out of range");
1007 		}
1008 	}
1009 
1010 	protected override void updateParticle(Particle particle, float deltaTime) {
1011 		particle.color = _color;
1012 	}
1013 
1014 	override FilterProperty[] getProperties() const {
1015 		return [
1016 			tuple("Rayon", 1f, 1000f, 999u),
1017 			tuple("Rouge", 0f, 1f, 256u),
1018 			tuple("Vert", 0f, 1f, 256u),
1019 			tuple("Bleu", 0f, 1f, 256u),
1020 			tuple("Alpha", 0f, 1f, 256u)
1021 			];
1022 	}
1023 
1024 	override FilterDisplay getDisplay() const {
1025 		Color color = _color;
1026 		color.a = 1f;
1027 		return tuple("Couleur", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, cast(const Color)color);
1028 	}
1029 }
1030 
1031 final class SetColorFilterRect: ParticleFilter {
1032 	private	Color _color;
1033 
1034 	this() {
1035 		_id = 17;
1036 		_nbProperties = 6U;
1037 		_isCircle = false;
1038 	}
1039 
1040 	override float property(uint id) const {
1041 		switch(id) {
1042 		case 0:
1043 			return _size.x;
1044 		case 1:
1045 			return _size.y;
1046 		case 2:
1047 			return _color.r;
1048 		case 3:
1049 			return _color.g;
1050 		case 4:
1051 			return _color.b;
1052 		case 5:
1053 			return _color.a;
1054 		default:
1055 			throw new Exception("Filter property out of range");
1056 		}
1057 	}
1058 
1059 	override void property(uint id, float newValue) {
1060 		switch(id) {
1061 		case 0:
1062 			_size.x = newValue;
1063 			break;
1064 		case 1:
1065 			_size.y = newValue;
1066 			break;
1067 		case 2:
1068 			_color.r = newValue;
1069 			break;
1070 		case 3:
1071 			_color.g = newValue;
1072 			break;
1073 		case 4:
1074 			_color.b = newValue;
1075 			break;
1076 		case 5:
1077 			_color.a = newValue;
1078 			break;
1079 		default:
1080 			throw new Exception("Filter property out of range");
1081 		}
1082 	}
1083 
1084 	protected override void updateParticle(Particle particle, float deltaTime) {
1085 		particle.color = _color;
1086 	}
1087 
1088 	override FilterProperty[] getProperties() const {
1089 		return [
1090 			tuple("Longueur", 2f, 2000f, 1998u),
1091 			tuple("Hauteur", 2f, 2000f, 1998u),
1092 			tuple("Rouge", 0f, 1f, 256u),
1093 			tuple("Vert", 0f, 1f, 256u),
1094 			tuple("Bleu", 0f, 1f, 256u),
1095 			tuple("Alpha", 0f, 1f, 256u)
1096 			];
1097 	}
1098 
1099 	override FilterDisplay getDisplay() const {
1100 		Color color = _color;
1101 		color.a = 1f;
1102 		return tuple("Couleur", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, cast(const Color)color);
1103 	}
1104 }
1105 
1106 
1107 //MixColor Filter
1108 final class MixColorFilterCircle: ParticleFilter {
1109 	private	{
1110 		Color _color;
1111 		float _blend = 1f;
1112 	}
1113 
1114 	this() {
1115 		_id = 18;
1116 		_nbProperties = 6U;
1117 		_isCircle = true;
1118 	}
1119 
1120 	override float property(uint id) const {
1121 		switch(id) {
1122 		case 0:
1123 			return _size.x;
1124 		case 1:
1125 			return _color.r;
1126 		case 2:
1127 			return _color.g;
1128 		case 3:
1129 			return _color.b;
1130 		case 4:
1131 			return _color.a;
1132 		case 5:
1133 			return _blend;
1134 		default:
1135 			throw new Exception("Filter property out of range");
1136 		}
1137 	}
1138 
1139 	override void property(uint id, float newValue) {
1140 		switch(id) {
1141 		case 0:
1142 			_size.x = newValue;
1143 			_size.y = newValue;
1144 			break;
1145 		case 1:
1146 			_color.r = newValue;
1147 			break;
1148 		case 2:
1149 			_color.g = newValue;
1150 			break;
1151 		case 3:
1152 			_color.b = newValue;
1153 			break;
1154 		case 4:
1155 			_color.a = newValue;
1156 			break;
1157 		case 5:
1158 			_blend = newValue;
1159 			break;
1160 		default:
1161 			throw new Exception("Filter property out of range");
1162 		}
1163 	}
1164 
1165 	protected override void updateParticle(Particle particle, float deltaTime) {
1166 		particle.color = lerp(particle.color, _color, _blend * deltaTime);
1167 	}
1168 
1169 	override FilterProperty[] getProperties() const {
1170 		return [
1171 			tuple("Rayon", 1f, 1000f, 999u),
1172 			tuple("Rouge", 0f, 1f, 256u),
1173 			tuple("Vert", 0f, 1f, 256u),
1174 			tuple("Bleu", 0f, 1f, 256u),
1175 			tuple("Alpha", 0f, 1f, 256u),
1176 			tuple("Mélange", .001f, .1f, 1000u)
1177 			];
1178 	}
1179 
1180 	override FilterDisplay getDisplay() const {
1181 		Color color = _color;
1182 		color.a = 1f;
1183 		return tuple("Couleur", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, cast(const Color)color);
1184 	}
1185 }
1186 
1187 final class MixColorFilterRect: ParticleFilter {
1188 	private	{
1189 		Color _color;
1190 		float _blend = 1f;
1191 	}
1192 
1193 	this() {
1194 		_id = 19;
1195 		_nbProperties = 7U;
1196 		_isCircle = false;
1197 	}
1198 
1199 	override float property(uint id) const {
1200 		switch(id) {
1201 		case 0:
1202 			return _size.x;
1203 		case 1:
1204 			return _size.y;
1205 		case 2:
1206 			return _color.r;
1207 		case 3:
1208 			return _color.g;
1209 		case 4:
1210 			return _color.b;
1211 		case 5:
1212 			return _color.a;
1213 		case 6:
1214 			return _blend;
1215 		default:
1216 			throw new Exception("Filter property out of range");
1217 		}
1218 	}
1219 
1220 	override void property(uint id, float newValue) {
1221 		switch(id) {
1222 		case 0:
1223 			_size.x = newValue;
1224 			break;
1225 		case 1:
1226 			_size.y = newValue;
1227 			break;
1228 		case 2:
1229 			_color.r = newValue;
1230 			break;
1231 		case 3:
1232 			_color.g = newValue;
1233 			break;
1234 		case 4:
1235 			_color.b = newValue;
1236 			break;
1237 		case 5:
1238 			_color.a = newValue;
1239 			break;
1240 		case 6:
1241 			_blend = newValue;
1242 			break;
1243 		default:
1244 			throw new Exception("Filter property out of range");
1245 		}
1246 	}
1247 
1248 	protected override void updateParticle(Particle particle, float deltaTime) {
1249 		particle.color = lerp(particle.color, _color, _blend * deltaTime);
1250 	}
1251 
1252 	override FilterProperty[] getProperties() const {
1253 		return [
1254 			tuple("Longueur", 2f, 2000f, 1998u),
1255 			tuple("Hauteur", 2f, 2000f, 1998u),
1256 			tuple("Rouge", 0f, 1f, 256u),
1257 			tuple("Vert", 0f, 1f, 256u),
1258 			tuple("Bleu", 0f, 1f, 256u),
1259 			tuple("Alpha", 0f, 1f, 256u),
1260 			tuple("Mélange", .001f, .1f, 1000u)
1261 			];
1262 	}
1263 
1264 	override FilterDisplay getDisplay() const {
1265 		Color color = _color;
1266 		color.a = 1f;
1267 		return tuple("Couleur", _isCircle, _size, false, cast(const Vec2f)Vec2f.zero, cast(const Color)color);
1268 	}
1269 }+/