1 /*
2 * Clutter.
3 *
4 * An OpenGL based 'interactive canvas' library.
5 *
6 * Authored By Matthew Allum <mallum@openedhand.com>
7 * Jorn Baayen <jorn@openedhand.com>
8 * Emmanuele Bassi <ebassi@openedhand.com>
9 * Tomas Frydrych <tf@openedhand.com>
10 *
11 * Copyright (C) 2006, 2007 OpenedHand
12 *
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2 of the License, or (at your option) any later version.
17 *
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
22 *
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the
25 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 * Boston, MA 02111-1307, USA.
27 */
28
29 /**
30 * SECTION:egg-alpha
31 * @short_description: A class for calculating an alpha value as a function
32 * of time.
33 *
34 * #EggAlpha is a class for calculating an integer value between
35 * 0 and %EGG_ALPHA_MAX_ALPHA as a function of time. You should
36 * provide a #EggTimeline and bind it to the #EggAlpha object;
37 * you should also provide a function returning the alpha value depending
38 * on the position inside the timeline; this function will be executed
39 * each time a new frame in the #EggTimeline is reached. Since the
40 * alpha function is controlled by the timeline instance, you can pause
41 * or stop the #EggAlpha from calling the alpha function by controlling
42 * the #EggTimeline object.
43 *
44 * #EggAlpha is used to "drive" a #EggBehaviour instance.
45 *
46 * <figure id="alpha-functions">
47 * <title>Graphic representation of some alpha functions</title>
48 * <graphic fileref="alpha-func.png" format="PNG"/>
49 * </figure>
50 *
51 * Since: 0.2
52 */
53
54 #ifdef HAVE_CONFIG_H
55 #include "config.h"
56 #endif
57
58 #include <math.h>
59
60 #include "egg-alpha.h"
61 #include "egg-hack.h"
62 // #include "egg-marshal.h"
63 // #include "egg-private.h"
64 #include "egg-debug.h"
65
66 G_DEFINE_TYPE (EggAlpha, egg_alpha, G_TYPE_INITIALLY_UNOWNED);
67
68
69 struct _EggAlphaPrivate
70 {
71 EggTimeline *timeline;
72 guint timeline_new_frame_id;
73
74 guint32 alpha;
75
76 GClosure *closure;
77 };
78
79 enum
80 {
81 PROP_0,
82
83 PROP_TIMELINE,
84 PROP_ALPHA
85 };
86
87 static void
88 timeline_new_frame_cb (EggTimeline *timeline,
89 guint current_frame_num,
90 EggAlpha *alpha)
91 {
92 EggAlphaPrivate *priv = alpha->priv;
93
94 /* Update alpha value and notify */
95 priv->alpha = egg_alpha_get_alpha (alpha);
96 g_object_notify (G_OBJECT (alpha), "alpha");
97 }
98
99 static void
100 egg_alpha_set_property (GObject *object,
101 guint prop_id,
102 const GValue *value,
103 GParamSpec *pspec)
104 {
105 EggAlpha *alpha;
106
107 alpha = EGG_ALPHA (object);
108
109 switch (prop_id)
110 {
111 case PROP_TIMELINE:
112 egg_alpha_set_timeline (alpha, g_value_get_object (value));
113 break;
114 default:
115 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
116 break;
117 }
118 }
119
120 static void
121 egg_alpha_get_property (GObject *object,
122 guint prop_id,
123 GValue *value,
124 GParamSpec *pspec)
125 {
126 EggAlpha *alpha;
127 EggAlphaPrivate *priv;
128
129 alpha = EGG_ALPHA (object);
130 priv = alpha->priv;
131
132 switch (prop_id)
133 {
134 case PROP_TIMELINE:
135 g_value_set_object (value, priv->timeline);
136 break;
137 case PROP_ALPHA:
138 g_value_set_uint (value, priv->alpha);
139 break;
140 default:
141 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
142 break;
143 }
144 }
145
146 static void
147 egg_alpha_finalize (GObject *object)
148 {
149 EggAlphaPrivate *priv = EGG_ALPHA (object)->priv;
150
151 if (priv->closure)
152 g_closure_unref (priv->closure);
153
154 G_OBJECT_CLASS (egg_alpha_parent_class)->finalize (object);
155 }
156
157 static void
158 egg_alpha_dispose (GObject *object)
159 {
160 EggAlpha *self = EGG_ALPHA(object);
161
162 egg_alpha_set_timeline (self, NULL);
163
164 G_OBJECT_CLASS (egg_alpha_parent_class)->dispose (object);
165 }
166
167
168 static void
169 egg_alpha_class_init (EggAlphaClass *klass)
170 {
171 GObjectClass *object_class = G_OBJECT_CLASS (klass);
172
173 object_class->set_property = egg_alpha_set_property;
174 object_class->get_property = egg_alpha_get_property;
175 object_class->finalize = egg_alpha_finalize;
176 object_class->dispose = egg_alpha_dispose;
177
178 g_type_class_add_private (klass, sizeof (EggAlphaPrivate));
179
180 /**
181 * EggAlpha:timeline:
182 *
183 * A #EggTimeline instance used to drive the alpha function.
184 *
185 * Since: 0.2
186 */
187 g_object_class_install_property (object_class,
188 PROP_TIMELINE,
189 g_param_spec_object ("timeline",
190 "Timeline",
191 "Timeline",
192 EGG_TYPE_TIMELINE,
193 EGG_PARAM_READWRITE));
194 /**
195 * EggAlpha:alpha:
196 *
197 * The alpha value as computed by the alpha function.
198 *
199 * Since: 0.2
200 */
201 g_object_class_install_property (object_class,
202 PROP_ALPHA,
203 g_param_spec_uint ("alpha",
204 "Alpha value",
205 "Alpha value",
206 0,
207 EGG_ALPHA_MAX_ALPHA,
208 0,
209 EGG_PARAM_READABLE));
210 }
211
212 static void
213 egg_alpha_init (EggAlpha *self)
214 {
215 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
216 EGG_TYPE_ALPHA,
217 EggAlphaPrivate);
218 }
219
220 /**
221 * egg_alpha_get_alpha:
222 * @alpha: A #EggAlpha
223 *
224 * Query the current alpha value.
225 *
226 * Return Value: The current alpha value for the alpha
227 *
228 * Since: 0.2
229 */
230 guint32
231 egg_alpha_get_alpha (EggAlpha *alpha)
232 {
233 EggAlphaPrivate *priv;
234 guint32 retval = 0;
235
236 g_return_val_if_fail (EGG_IS_ALPHA (alpha), 0);
237
238 priv = alpha->priv;
239
240 if (G_LIKELY (priv->closure))
241 {
242 GValue params = { 0, };
243 GValue result_value = { 0, };
244
245 g_object_ref (alpha);
246
247 g_value_init (&result_value, G_TYPE_UINT);
248
249 g_value_init (¶ms, EGG_TYPE_ALPHA);
250 g_value_set_object (¶ms, alpha);
251
252 g_closure_invoke (priv->closure,
253 &result_value,
254 1,
255 ¶ms,
256 NULL);
257
258 retval = g_value_get_uint (&result_value);
259
260 g_value_unset (&result_value);
261 g_value_unset (¶ms);
262
263 g_object_unref (alpha);
264 }
265
266 return retval;
267 }
268
269 /**
270 * egg_alpha_set_closure:
271 * @alpha: A #EggAlpha
272 * @closure: A #GClosure
273 *
274 * Sets the #GClosure used to compute
275 * the alpha value at each frame of the #EggTimeline
276 * bound to @alpha.
277 *
278 * Since: 0.8
279 */
280 void
281 egg_alpha_set_closure (EggAlpha *alpha,
282 GClosure *closure)
283 {
284 EggAlphaPrivate *priv;
285
286 g_return_if_fail (EGG_IS_ALPHA (alpha));
287 g_return_if_fail (closure != NULL);
288
289 priv = alpha->priv;
290
291 if (priv->closure)
292 g_closure_unref (priv->closure);
293
294 priv->closure = g_closure_ref (closure);
295 g_closure_sink (closure);
296
297 if (G_CLOSURE_NEEDS_MARSHAL (closure))
298 {
299 GClosureMarshal marshal = egg_marshal_UINT__VOID;
300
301 g_closure_set_marshal (closure, marshal);
302 }
303 }
304
305 /**
306 * egg_alpha_set_func:
307 * @alpha: A #EggAlpha
308 * @func: A #EggAlphaAlphaFunc
309 * @data: user data to be passed to the alpha function, or %NULL
310 * @destroy: notify function used when disposing the alpha function
311 *
312 * Sets the #EggAlphaFunc function used to compute
313 * the alpha value at each frame of the #EggTimeline
314 * bound to @alpha.
315 *
316 * Since: 0.2
317 */
318 void
319 egg_alpha_set_func (EggAlpha *alpha,
320 EggAlphaFunc func,
321 gpointer data,
322 GDestroyNotify destroy)
323 {
324 GClosure *closure;
325
326 g_return_if_fail (EGG_IS_ALPHA (alpha));
327 g_return_if_fail (func != NULL);
328
329 closure = g_cclosure_new (G_CALLBACK (func), data, (GClosureNotify) destroy);
330 egg_alpha_set_closure (alpha, closure);
331 }
332
333 /**
334 * egg_alpha_set_timeline:
335 * @alpha: A #EggAlpha
336 * @timeline: A #EggTimeline
337 *
338 * Binds @alpha to @timeline.
339 *
340 * Since: 0.2
341 */
342 void
343 egg_alpha_set_timeline (EggAlpha *alpha,
344 EggTimeline *timeline)
345 {
346 EggAlphaPrivate *priv;
347
348 g_return_if_fail (EGG_IS_ALPHA (alpha));
349 g_return_if_fail (timeline == NULL || EGG_IS_TIMELINE (timeline));
350
351 priv = alpha->priv;
352
353 if (priv->timeline)
354 {
355 g_signal_handlers_disconnect_by_func (priv->timeline,
356 timeline_new_frame_cb,
357 alpha);
358
359 g_object_unref (priv->timeline);
360 priv->timeline = NULL;
361 }
362
363 if (timeline)
364 {
365 priv->timeline = g_object_ref (timeline);
366
367 g_signal_connect (priv->timeline, "new-frame",
368 G_CALLBACK (timeline_new_frame_cb),
369 alpha);
370 }
371 }
372
373 /**
374 * egg_alpha_get_timeline:
375 * @alpha: A #EggAlpha
376 *
377 * Gets the #EggTimeline bound to @alpha.
378 *
379 * Return value: a #EggTimeline instance
380 *
381 * Since: 0.2
382 */
383 EggTimeline *
384 egg_alpha_get_timeline (EggAlpha *alpha)
385 {
386 g_return_val_if_fail (EGG_IS_ALPHA (alpha), NULL);
387
388 return alpha->priv->timeline;
389 }
390
391 /**
392 * egg_alpha_new:
393 *
394 * Creates a new #EggAlpha instance. You must set a function
395 * to compute the alpha value using egg_alpha_set_func() and
396 * bind a #EggTimeline object to the #EggAlpha instance
397 * using egg_alpha_set_timeline().
398 *
399 * You should use the newly created #EggAlpha instance inside
400 * a #EggBehaviour object.
401 *
402 * Return value: the newly created empty #EggAlpha instance.
403 *
404 * Since: 0.2
405 */
406 EggAlpha *
407 egg_alpha_new (void)
408 {
409 return g_object_new (EGG_TYPE_ALPHA, NULL);
410 }
411
412 /**
413 * egg_alpha_new_full:
414 * @timeline: #EggTimeline timeline
415 * @func: #EggAlphaFunc alpha function
416 * @data: data to be passed to the alpha function
417 * @destroy: notify to be called when removing the alpha function
418 *
419 * Creates a new #EggAlpha instance and sets the timeline
420 * and alpha function.
421 *
422 * Return Value: the newly created #EggAlpha
423 *
424 * Since: 0.2
425 */
426 EggAlpha *
427 egg_alpha_new_full (EggTimeline *timeline,
428 EggAlphaFunc func,
429 gpointer data,
430 GDestroyNotify destroy)
431 {
432 EggAlpha *retval;
433
434 g_return_val_if_fail (EGG_IS_TIMELINE (timeline), NULL);
435 g_return_val_if_fail (func != NULL, NULL);
436
437 retval = egg_alpha_new ();
438
439 egg_alpha_set_timeline (retval, timeline);
440 egg_alpha_set_func (retval, func, data, destroy);
441
442 return retval;
443 }
444
445 /**
446 * EGG_ALPHA_RAMP_INC:
447 *
448 * Convenience symbol for egg_ramp_inc_func().
449 *
450 * Since: 0.2
451 */
452
453 /**
454 * egg_ramp_inc_func:
455 * @alpha: a #EggAlpha
456 * @dummy: unused argument
457 *
458 * Convenience alpha function for a monotonic increasing ramp. You
459 * can use this function as the alpha function for egg_alpha_set_func().
460 *
461 * Return value: an alpha value.
462 *
463 * Since: 0.2
464 */
465 guint32
466 egg_ramp_inc_func (EggAlpha *alpha,
467 gpointer dummy)
468 {
469 EggTimeline *timeline;
470 gint current_frame_num, n_frames;
471
472 timeline = egg_alpha_get_timeline (alpha);
473
474 current_frame_num = egg_timeline_get_current_frame (timeline);
475 n_frames = egg_timeline_get_n_frames (timeline);
476
477 return (current_frame_num * EGG_ALPHA_MAX_ALPHA) / n_frames;
478 }
479
480 /**
481 * EGG_ALPHA_RAMP_DEC:
482 *
483 * Convenience symbol for egg_ramp_dec_func().
484 *
485 * Since: 0.2
486 */
487
488 /**
489 * egg_ramp_dec_func:
490 * @alpha: a #EggAlpha
491 * @dummy: unused argument
492 *
493 * Convenience alpha function for a monotonic decreasing ramp. You
494 * can use this function as the alpha function for egg_alpha_set_func().
495 *
496 * Return value: an alpha value.
497 *
498 * Since: 0.2
499 */
500 guint32
501 egg_ramp_dec_func (EggAlpha *alpha,
502 gpointer dummy)
503 {
504 EggTimeline *timeline;
505 gint current_frame_num, n_frames;
506
507 timeline = egg_alpha_get_timeline (alpha);
508
509 current_frame_num = egg_timeline_get_current_frame (timeline);
510 n_frames = egg_timeline_get_n_frames (timeline);
511
512 return (n_frames - current_frame_num)
513 * EGG_ALPHA_MAX_ALPHA
514 / n_frames;
515 }
516
517 /**
518 * EGG_ALPHA_RAMP:
519 *
520 * Convenience symbol for egg_ramp_func().
521 *
522 * Since: 0.2
523 */
524
525 /**
526 * egg_ramp_func:
527 * @alpha: a #EggAlpha
528 * @dummy: unused argument
529 *
530 * Convenience alpha function for a full ramp function (increase for
531 * half the time, decrease for the remaining half). You can use this
532 * function as the alpha function for egg_alpha_set_func().
533 *
534 * Return value: an alpha value.
535 *
536 * Since: 0.2
537 */
538 guint32
539 egg_ramp_func (EggAlpha *alpha,
540 gpointer dummy)
541 {
542 EggTimeline *timeline;
543 gint current_frame_num, n_frames;
544
545 timeline = egg_alpha_get_timeline (alpha);
546
547 current_frame_num = egg_timeline_get_current_frame (timeline);
548 n_frames = egg_timeline_get_n_frames (timeline);
549
550 if (current_frame_num > (n_frames / 2))
551 {
552 return (n_frames - current_frame_num)
553 * EGG_ALPHA_MAX_ALPHA
554 / (n_frames / 2);
555 }
556 else
557 {
558 return current_frame_num
559 * EGG_ALPHA_MAX_ALPHA
560 / (n_frames / 2);
561 }
562 }
563
564 static guint32
565 sincx1024_func (EggAlpha *alpha,
566 EggAngle angle,
567 EggFixed offset)
568 {
569 EggTimeline *timeline;
570 gint current_frame_num, n_frames;
571 EggAngle x;
572 unsigned int sine;
573
574 timeline = egg_alpha_get_timeline (alpha);
575
576 current_frame_num = egg_timeline_get_current_frame (timeline);
577 n_frames = egg_timeline_get_n_frames (timeline);
578
579 x = angle * current_frame_num / n_frames;
580
581 x -= (512 * 512 / angle);
582
583 sine = ((egg_sini (x) + offset)/2) * EGG_ALPHA_MAX_ALPHA;
584
585 sine = sine >> CFX_Q;
586
587 return sine;
588 }
589 #if 0
590 /*
591 * The following two functions are left in place for reference
592 * purposes.
593 */
594 static guint32
595 sincx_func (EggAlpha *alpha,
596 EggFixed angle,
597 EggFixed offset)
598 {
599 EggTimeline *timeline;
600 gint current_frame_num, n_frames;
601 EggFixed x, sine;
602
603 timeline = egg_alpha_get_timeline (alpha);
604
605 current_frame_num = egg_timeline_get_current_frame (timeline);
606 n_frames = egg_timeline_get_n_frames (timeline);
607
608 x = angle * current_frame_num / n_frames;
609 x = EGG_FIXED_MUL (x, CFX_PI) - EGG_FIXED_DIV (CFX_PI, angle);
610
611 sine = (egg_fixed_sin (x) + offset)/2;
612
613 EGG_NOTE (ALPHA, "sine: %2f\n", EGG_FIXED_TO_DOUBLE (sine));
614
615 return EGG_FIXED_TO_INT (sine * EGG_ALPHA_MAX_ALPHA);
616 }
617
618 /* NB: angle is not in radians but in muliples of PI, i.e., 2.0
619 * represents full circle.
620 */
621 static guint32
622 sinc_func (EggAlpha *alpha,
623 float angle,
624 float offset)
625 {
626 EggTimeline *timeline;
627 gint current_frame_num, n_frames;
628 gdouble x, sine;
629
630 timeline = egg_alpha_get_timeline (alpha);
631
632 current_frame_num = egg_timeline_get_current_frame (timeline);
633 n_frames = egg_timeline_get_n_frames (timeline);
634
635 /* FIXME: fixed point, and fixed point sine() */
636
637 x = (gdouble) (current_frame_num * angle * G_PI) / n_frames ;
638 sine = (sin (x - (G_PI / angle)) + offset) * 0.5f;
639
640 EGG_NOTE (ALPHA, "sine: %2f\n",sine);
641
642 return EGG_FLOAT_TO_INT ((sine * (gdouble) EGG_ALPHA_MAX_ALPHA));
643 }
644 #endif
645
646 /**
647 * EGG_ALPHA_SINE:
648 *
649 * Convenience symbol for egg_sine_func().
650 *
651 * Since: 0.2
652 */
653
654 /**
655 * egg_sine_func:
656 * @alpha: a #EggAlpha
657 * @dummy: unused argument
658 *
659 * Convenience alpha function for a sine wave. You can use this
660 * function as the alpha function for egg_alpha_set_func().
661 *
662 * Return value: an alpha value.
663 *
664 * Since: 0.2
665 */
666 guint32
667 egg_sine_func (EggAlpha *alpha,
668 gpointer dummy)
669 {
670 #if 0
671 return sinc_func (alpha, 2.0, 1.0);
672 #else
673 /* 2.0 above represents full circle */
674 return sincx1024_func (alpha, 1024, CFX_ONE);
675 #endif
676 }
677
678 /**
679 * EGG_ALPHA_SINE_INC:
680 *
681 * Convenience symbol for egg_sine_inc_func().
682 *
683 * Since: 0.2
684 */
685
686 /**
687 * egg_sine_inc_func:
688 * @alpha: a #EggAlpha
689 * @dummy: unused argument
690 *
691 * Convenience alpha function for a sine wave over interval [0, pi / 2].
692 * You can use this function as the alpha function for
693 * egg_alpha_set_func().
694 *
695 * Return value: an alpha value.
696 *
697 * Since: 0.2
698 */
699 guint32
700 egg_sine_inc_func (EggAlpha *alpha,
701 gpointer dummy)
702 {
703 EggTimeline * timeline;
704 gint frame;
705 gint n_frames;
706 EggAngle x;
707 EggFixed sine;
708
709 timeline = egg_alpha_get_timeline (alpha);
710 frame = egg_timeline_get_current_frame (timeline);
711 n_frames = egg_timeline_get_n_frames (timeline);
712
713 x = 256 * frame / n_frames;
714
715 sine = egg_sini (x) * EGG_ALPHA_MAX_ALPHA;
716
717 return ((guint32)sine) >> CFX_Q;
718 }
719
720 /**
721 * EGG_ALPHA_SINE_DEC:
722 *
723 * Convenience symbol for egg_sine_dec_func().
724 *
725 * Since: 0.2
726 */
727
728 /**
729 * egg_sine_dec_func:
730 * @alpha: a #EggAlpha
731 * @dummy: unused argument
732 *
733 * Convenience alpha function for a sine wave over interval [pi / 2, pi].
734 * You can use this function as the alpha function for
735 * egg_alpha_set_func().
736 *
737 * Return value: an alpha value.
738 *
739 * Since: 0.4
740 */
741 guint32
742 egg_sine_dec_func (EggAlpha *alpha,
743 gpointer dummy)
744 {
745 EggTimeline * timeline;
746 gint frame;
747 gint n_frames;
748 EggAngle x;
749 EggFixed sine;
750
751 timeline = egg_alpha_get_timeline (alpha);
752 frame = egg_timeline_get_current_frame (timeline);
CID 10937 - DIVIDE_BY_ZERO
On this path, function call "egg_timeline_get_n_frames(timeline)" has return value of 0
Assigning: "n_frames" = "egg_timeline_get_n_frames(timeline)".
753 n_frames = egg_timeline_get_n_frames (timeline);
754
CID 10937 - DIVIDE_BY_ZERO
In expression "256 * frame / n_frames", division by expression "n_frames" which may be zero has undefined behavior.
755 x = 256 * frame / n_frames + 256;
756
757 sine = egg_sini (x) * EGG_ALPHA_MAX_ALPHA;
758
759 return ((guint32)sine) >> CFX_Q;
760 }
761
762 /**
763 * EGG_ALPHA_SINE_HALF:
764 *
765 * Convenience symbol for egg_sine_half_func().
766 *
767 * Since: 0.4
768 */
769
770 /**
771 * egg_sine_half_func:
772 * @alpha: a #EggAlpha
773 * @dummy: unused argument
774 *
775 * Convenience alpha function for a sine wave over interval [0, pi].
776 * You can use this function as the alpha function for
777 * egg_alpha_set_func().
778 *
779 * Return value: an alpha value.
780 *
781 * Since: 0.4
782 */
783 guint32
784 egg_sine_half_func (EggAlpha *alpha,
785 gpointer dummy)
786 {
787 EggTimeline * timeline;
788 gint frame;
789 gint n_frames;
790 EggAngle x;
791 EggFixed sine;
792
793 timeline = egg_alpha_get_timeline (alpha);
794 frame = egg_timeline_get_current_frame (timeline);
795 n_frames = egg_timeline_get_n_frames (timeline);
796
797 x = 512 * frame / n_frames;
798
799 sine = egg_sini (x) * EGG_ALPHA_MAX_ALPHA;
800
801 return ((guint32)sine) >> CFX_Q;
802 }
803
804 /**
805 * EGG_ALPHA_SQUARE:
806 *
807 * Convenience symbol for egg_square_func().
808 *
809 * Since: 0.4
810 */
811
812 /**
813 * egg_square_func:
814 * @alpha: a #EggAlpha
815 * @dummy: unused argument
816 *
817 * Convenience alpha function for a square wave. You can use this
818 * function as the alpha function for egg_alpha_set_func().
819 *
820 * Return value: an alpha value
821 *
822 * Since: 0.4
823 */
824 guint32
825 egg_square_func (EggAlpha *alpha,
826 gpointer dummy)
827 {
828 EggTimeline *timeline;
829 gint current_frame_num, n_frames;
830
831 timeline = egg_alpha_get_timeline (alpha);
832
833 current_frame_num = egg_timeline_get_current_frame (timeline);
834 n_frames = egg_timeline_get_n_frames (timeline);
835
836 return (current_frame_num > (n_frames / 2)) ? EGG_ALPHA_MAX_ALPHA
837 : 0;
838 }
839
840 /**
841 * EGG_ALPHA_SMOOTHSTEP_INC:
842 *
843 * Convenience symbol for egg_smoothstep_inc_func().
844 *
845 * Since: 0.4
846 */
847
848 /**
849 * egg_smoothstep_inc_func:
850 * @alpha: a #EggAlpha
851 * @dummy: unused
852 *
853 * Convenience alpha function for a smoothstep curve. You can use this
854 * function as the alpha function for egg_alpha_set_func().
855 *
856 * Return value: an alpha value
857 *
858 * Since: 0.4
859 */
860 guint32
861 egg_smoothstep_inc_func (EggAlpha *alpha,
862 gpointer dummy)
863 {
864 EggTimeline *timeline;
865 gint frame;
866 gint n_frames;
867 guint32 r;
868 guint32 x;
869
870 /*
871 * The smoothstep function uses f(x) = -2x^3 + 3x^2 where x is from <0,1>,
872 * and precission is critical -- we use 8.24 fixed format for this operation.
873 * The earlier operations involve division, which we cannot do in 8.24 for
874 * numbers in <0,1> we use EggFixed.
875 */
876 timeline = egg_alpha_get_timeline (alpha);
877 frame = egg_timeline_get_current_frame (timeline);
878 n_frames = egg_timeline_get_n_frames (timeline);
879
880 /*
881 * Convert x to 8.24 for next step.
882 */
883 x = CFX_DIV (frame, n_frames) << 8;
884
885 /*
886 * f(x) = -2x^3 + 3x^2
887 *
888 * Convert result to EggFixed to avoid overflow in next step.
889 */
890 r = ((x >> 12) * (x >> 12) * 3 - (x >> 15) * (x >> 16) * (x >> 16)) >> 8;
891
892 return CFX_INT (r * EGG_ALPHA_MAX_ALPHA);
893 }
894
895 /**
896 * EGG_ALPHA_SMOOTHSTEP_DEC:
897 *
898 * Convenience symbol for egg_smoothstep_dec_func().
899 *
900 * Since: 0.4
901 */
902
903 /**
904 * egg_smoothstep_dec_func:
905 * @alpha: a #EggAlpha
906 * @dummy: unused
907 *
908 * Convenience alpha function for a downward smoothstep curve. You can use
909 * this function as the alpha function for egg_alpha_set_func().
910 *
911 * Return value: an alpha value
912 *
913 * Since: 0.4
914 */
915 guint32
916 egg_smoothstep_dec_func (EggAlpha *alpha,
917 gpointer dummy)
918 {
919 return EGG_ALPHA_MAX_ALPHA - egg_smoothstep_inc_func (alpha, dummy);
920 }
921
922 /**
923 * EGG_ALPHA_EXP_INC:
924 *
925 * Convenience symbol for egg_exp_inc_func()
926 *
927 * Since: 0.4
928 */
929
930 /**
931 * egg_exp_inc_func:
932 * @alpha: a #EggAlpha
933 * @dummy: unused argument
934 *
935 * Convenience alpha function for a 2^x curve. You can use this function as the
936 * alpha function for egg_alpha_set_func().
937 *
938 * Return value: an alpha value.
939 *
940 * Since: 0.4
941 */
942 guint32
943 egg_exp_inc_func (EggAlpha *alpha,
944 gpointer dummy)
945 {
946 EggTimeline * timeline;
947 gint frame;
948 gint n_frames;
949 EggFixed x;
950 EggFixed x_alpha_max = 0x100000;
951 guint32 result;
952
953 /*
954 * Choose x_alpha_max such that
955 *
956 * (2^x_alpha_max) - 1 == EGG_ALPHA_MAX_ALPHA
957 */
958 #if EGG_ALPHA_MAX_ALPHA != 0xffff
959 #error Adjust x_alpha_max to match EGG_ALPHA_MAX_ALPHA
960 #endif
961
962 timeline = egg_alpha_get_timeline (alpha);
963 frame = egg_timeline_get_current_frame (timeline);
964 n_frames = egg_timeline_get_n_frames (timeline);
965
966 x = x_alpha_max * frame / n_frames;
967
968 result = CLAMP (egg_pow2x (x) - 1, 0, EGG_ALPHA_MAX_ALPHA);
969
970 return result;
971 }
972
973 /**
974 * EGG_ALPHA_EXP_DEC:
975 *
976 * Convenience symbold for egg_exp_dec_func().
977 *
978 * Since: 0.4
979 */
980
981 /**
982 * egg_exp_dec_func:
983 * @alpha: a #EggAlpha
984 * @dummy: unused argument
985 *
986 * Convenience alpha function for a decreasing 2^x curve. You can use this
987 * function as the alpha function for egg_alpha_set_func().
988 *
989 * Return value: an alpha value.
990 *
991 * Since: 0.4
992 */
993 guint32
994 egg_exp_dec_func (EggAlpha *alpha,
995 gpointer dummy)
996 {
997 EggTimeline * timeline;
998 gint frame;
999 gint n_frames;
1000 EggFixed x;
1001 EggFixed x_alpha_max = 0x100000;
1002 guint32 result;
1003
1004 /*
1005 * Choose x_alpha_max such that
1006 *
1007 * (2^x_alpha_max) - 1 == EGG_ALPHA_MAX_ALPHA
1008 */
1009 #if EGG_ALPHA_MAX_ALPHA != 0xffff
1010 #error Adjust x_alpha_max to match EGG_ALPHA_MAX_ALPHA
1011 #endif
1012
1013 timeline = egg_alpha_get_timeline (alpha);
1014 frame = egg_timeline_get_current_frame (timeline);
1015 n_frames = egg_timeline_get_n_frames (timeline);
1016
1017 x = (x_alpha_max * (n_frames - frame)) / n_frames;
1018
1019 result = CLAMP (egg_pow2x (x) - 1, 0, EGG_ALPHA_MAX_ALPHA);
1020
1021 return result;
1022 }