Logo Search packages:      
Sourcecode: lebiniou version File versions  Download package

zebu1.c

/*
 *  Copyright 1994-2011 Olivier Girondel
 *
 *  This file is part of lebiniou.
 *
 *  lebiniou is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  lebiniou is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with lebiniou. If not, see <http://www.gnu.org/licenses/>.
 */

#include "constants.h"
#include "context.h"


u_long id = 1177412508;
u_long options = BE_SFX2D;
u_long mode = OVERLAY;
char desc[] = "Zebulon effect";


/*
 * Optimisation :
 * Les spheres ayant toutes le meme rayon dans une meme image,
 * on va precalculer l'index de couleur d'une sphere dans une grille.
 */


00037 typedef struct position {
  u_short x, y;
} POSITION;

/* Nombre total de spheres */
#define NB_SPHERES 16

/* Rayon max : hauteur ecran / 12 */
#define RADIUS(h)  ((h)/12)

/* Centre des spheres */
static POSITION centres[NB_SPHERES];

/* Rayon d'une sphere */
static u_short rayon;

/** Rayon maxi **/
static u_short rayon_maxi;

/* Cote maximum de la grille des index couleur */
static u_short cote_maxi;

/* Grille des index, dans sa taille maximale */
static Pixel_t *index_couleurs;


/* Allouer un buffer pour une sphere */
inline static void
alloue_sphere()
{
  size_t n;
  /* Rayon maxi pour cette taille d'ecran */
  rayon_maxi = (u_short) RADIUS(HEIGHT);
  /* cote du buffer conteneur */
  cote_maxi = (rayon_maxi << 1) + 1;
  /* Allocation du buffer */
  n = (size_t) cote_maxi * cote_maxi;
  index_couleurs = (Pixel_t *) xcalloc(n, sizeof(Pixel_t));
}


/* Liberer la memoire allouee pour le buffer sphere */
inline static void
libere_sphere()
{
  xfree(index_couleurs);
}


/* Calculer le rayon d'une sphere */
inline static void
calcul_rayon(Context_t *ctx)
{
  float volume;

  volume = Input_get_volume(ctx->input);

  /** Ajustement du volume **/
  /* pow(volume, X) modifie la sensibilité du plugin :
   * comme volume est compris entre 0.0 et 1.0,
   * X > 0 ET X < 1 va "gonfler" la réponse (plus sensible sur petits volumes),
   * X > 1 va "plaquer" la réponse vers le bas (moins sensible sur petits
   * volumes, et meilleur pulse sur beats
   */
  /* et "* 50.0" pour réajuster le volume globalement, sinon on voit des
   * petits points en guise de sphères */
  volume = powf(volume, 3) * 50.0;

  /* Rayon d'une sphere */
  rayon = (u_short)(volume * rayon_maxi);
  if (rayon > rayon_maxi)
    rayon = rayon_maxi;
}


/* Calculer les index de couleur d'une sphere */
inline static void
calcul_index()
{
  if (rayon > 0)
  {
    Pixel_t *p = index_couleurs;
    float a, b;
    short dx, dy, r1;

    r1 = rayon - 1;
    for (dy = -r1; dy <= r1; dy++) {
      b = (float)dy / rayon;
      b *= b;
      for (dx = -r1; dx <= r1; dx++) {
        a = (float)dx / rayon;
        a *= a;
        a += b;
        a = floor(sqrtf(1 - a) * 255);
        if (a > 255)
          a = 255;
        else if (a < 0)
          a = 0;
        *p++ = (Pixel_t) a;
      }
    }
  }
}


/* Placer les spheres au hasard */
inline static void
place_spheres()
{
  u_short i, *p;

  p = (u_short *)centres;
  for (i = 0; i < NB_SPHERES; i++) {
    *p++ = (u_short)(b_rand_int() % WIDTH);
    *p++ = (u_short)(b_rand_int() % HEIGHT);
  }
}


/* Tracer une sphere */
inline static void
trace_sphere(Buffer8_t *dst, POSITION *pos)
{
  if (rayon > 0)
  {
    u_short x, y, r1;
    short dx, dy;
    Pixel_t index, *p = index_couleurs;

    r1 = rayon - 1;
    for (dy = -r1; dy <= r1; dy++) {
      y = (pos->y + HEIGHT + dy) % HEIGHT;
      for (dx = -r1; dx <= r1; dx++) {
        index = *p++;
        if (index > 0) {
          x = (pos->x + WIDTH + dx) % WIDTH;
          if (index > get_pixel_nc(dst, x, y))
            set_pixel_nc(dst, x, y, index);
        }
      }
    }
  }
}


/* Tracer toutes les spheres */
inline static void
trace_spheres(Context_t *ctx)
{
  u_short longueur, offset, i, n, *p;
  Buffer8_t *dst = passive_buffer(ctx);

  Buffer8_clear(dst);

  /* Deplacement maximal d'une sphere : +/- (rayon/4) */
  offset = rayon / 4;
  longueur = offset * 2 + 1;

  p = (u_short *)centres;
  for (i = 0; i < NB_SPHERES; i++) {
    trace_sphere(dst, (POSITION *)p);

    /* Deplacer la sphere */
    n = *p;
    *p++ = (u_short)((n + WIDTH  + (b_rand_int() % longueur) - offset) % WIDTH);
    n = *p;
    *p++ = (u_short)((n + HEIGHT + (b_rand_int() % longueur) - offset) % HEIGHT);
  }
}


void
create(Context_t *ctx)
{
  if (ctx->input == NULL)
    options |= BEQ_DISABLED;
  else
  {
    alloue_sphere();
    place_spheres();
  }
}


void
run(Context_t *ctx)
{
  if (ctx->input == NULL)
    return;

  calcul_rayon(ctx);
  calcul_index();
  trace_spheres(ctx);
}


void
on_switch_on(__attribute__ ((unused)) Context_t *ctx)
{
  place_spheres();
}

void
destroy(__attribute__ ((unused)) Context_t *ctx)
{
  libere_sphere();
}

Generated by  Doxygen 1.6.0   Back to index