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
timeline_new_frame_cb(EggTimeline * timeline,guint current_frame_num,EggAlpha * alpha)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
egg_alpha_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)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
egg_alpha_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)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
egg_alpha_finalize(GObject * object)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
egg_alpha_dispose(GObject * object)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
egg_alpha_class_init(EggAlphaClass * klass)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
egg_alpha_init(EggAlpha * self)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
egg_alpha_get_alpha(EggAlpha * alpha)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 (&params, EGG_TYPE_ALPHA);
250       g_value_set_object (&params, alpha);
251 
252       g_closure_invoke (priv->closure,
253                         &result_value,
254                         1,
255                         &params,
256                         NULL);
257 
258       retval = g_value_get_uint (&result_value);
259 
260       g_value_unset (&result_value);
261       g_value_unset (&params);
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
egg_alpha_set_closure(EggAlpha * alpha,GClosure * closure)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
egg_alpha_set_func(EggAlpha * alpha,EggAlphaFunc func,gpointer data,GDestroyNotify destroy)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
egg_alpha_set_timeline(EggAlpha * alpha,EggTimeline * timeline)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 *
egg_alpha_get_timeline(EggAlpha * alpha)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 *
egg_alpha_new(void)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 *
egg_alpha_new_full(EggTimeline * timeline,EggAlphaFunc func,gpointer data,GDestroyNotify destroy)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
egg_ramp_inc_func(EggAlpha * alpha,gpointer dummy)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
egg_ramp_dec_func(EggAlpha * alpha,gpointer dummy)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
egg_ramp_func(EggAlpha * alpha,gpointer dummy)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
sincx1024_func(EggAlpha * alpha,EggAngle angle,EggFixed offset)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
egg_sine_func(EggAlpha * alpha,gpointer dummy)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
egg_sine_inc_func(EggAlpha * alpha,gpointer dummy)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
egg_sine_dec_func(EggAlpha * alpha,gpointer dummy)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);
753   n_frames = egg_timeline_get_n_frames (timeline);
754 
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
egg_sine_half_func(EggAlpha * alpha,gpointer dummy)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
egg_square_func(EggAlpha * alpha,gpointer dummy)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
egg_smoothstep_inc_func(EggAlpha * alpha,gpointer dummy)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
egg_smoothstep_dec_func(EggAlpha * alpha,gpointer dummy)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
egg_exp_inc_func(EggAlpha * alpha,gpointer dummy)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
egg_exp_dec_func(EggAlpha * alpha,gpointer dummy)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 }
1023