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 (&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
 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);
 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 
 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);
CID 10933 - 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)".
 964   n_frames = egg_timeline_get_n_frames (timeline);
 965 
CID 10933 - DIVIDE_BY_ZERO
In expression "x_alpha_max * frame / n_frames", division by expression "n_frames" which may be zero has undefined behavior.
 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 }