/* Goom Project * Copyright (C) <2003> iOS-Software * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "goom_fx.h" #include "goom_plugin_info.h" #include "goom_tools.h" #include "mathtools.h" /* TODO:-- FAIRE PROPREMENT... BOAH... */ #define NCOL 15 /*static const int colval[] = { 0xfdf6f5, 0xfae4e4, 0xf7d1d1, 0xf3b6b5, 0xefa2a2, 0xec9190, 0xea8282, 0xe87575, 0xe46060, 0xe14b4c, 0xde3b3b, 0xdc2d2f, 0xd92726, 0xd81619, 0xd50c09, 0 }; */ static const int colval[] = { 0x1416181a, 0x1419181a, 0x141f181a, 0x1426181a, 0x142a181a, 0x142f181a, 0x1436181a, 0x142f1819, 0x14261615, 0x13201411, 0x111a100a, 0x0c180508, 0x08100304, 0x00050101, 0x0 }; /* The different modes of the visual FX. * Put this values on fx_mode */ #define FIREWORKS_FX 0 #define RAIN_FX 1 #define FOUNTAIN_FX 2 #define LAST_FX 3 typedef struct _FS_STAR { float x, y; float vx, vy; float ax, ay; float age, vage; } Star; typedef struct _FS_DATA { int fx_mode; int nbStars; int maxStars; Star *stars; float min_age; float max_age; PluginParam min_age_p; PluginParam max_age_p; PluginParam nbStars_p; PluginParam nbStars_limit_p; PluginParam fx_mode_p; PluginParameters params; } FSData; static void fs_init (VisualFX * _this, PluginInfo * info) { FSData *data; data = (FSData *) malloc (sizeof (FSData)); data->fx_mode = FIREWORKS_FX; data->maxStars = 4096; data->stars = (Star *) malloc (data->maxStars * sizeof (Star)); data->nbStars = 0; data->max_age_p = secure_i_param ("Fireworks Smallest Bombs"); IVAL (data->max_age_p) = 80; IMIN (data->max_age_p) = 0; IMAX (data->max_age_p) = 100; ISTEP (data->max_age_p) = 1; data->min_age_p = secure_i_param ("Fireworks Largest Bombs"); IVAL (data->min_age_p) = 99; IMIN (data->min_age_p) = 0; IMAX (data->min_age_p) = 100; ISTEP (data->min_age_p) = 1; data->nbStars_limit_p = secure_i_param ("Max Number of Particules"); IVAL (data->nbStars_limit_p) = 512; IMIN (data->nbStars_limit_p) = 0; IMAX (data->nbStars_limit_p) = data->maxStars; ISTEP (data->nbStars_limit_p) = 64; data->fx_mode_p = secure_i_param ("FX Mode"); IVAL (data->fx_mode_p) = data->fx_mode; IMIN (data->fx_mode_p) = 1; IMAX (data->fx_mode_p) = 3; ISTEP (data->fx_mode_p) = 1; data->nbStars_p = secure_f_feedback ("Number of Particules (% of Max)"); data->params = plugin_parameters ("Particule System", 7); data->params.params[0] = &data->fx_mode_p; data->params.params[1] = &data->nbStars_limit_p; data->params.params[2] = 0; data->params.params[3] = &data->min_age_p; data->params.params[4] = &data->max_age_p; data->params.params[5] = 0; data->params.params[6] = &data->nbStars_p; _this->params = &data->params; _this->fx_data = (void *) data; } static void fs_free (VisualFX * _this) { FSData *data = (FSData *) _this->fx_data; goom_plugin_parameters_free (&data->params); free (data->stars); free (_this->fx_data); } /** * Cree une nouvelle 'bombe', c'est a dire une particule appartenant a une fusee d'artifice. */ static void addABomb (FSData * fs, int mx, int my, float radius, float vage, float gravity, PluginInfo * info) { int i = fs->nbStars; float ro; int theta; if (fs->nbStars >= fs->maxStars) return; fs->nbStars++; fs->stars[i].x = mx; fs->stars[i].y = my; ro = radius * (float) goom_irand (info->gRandom, 100) / 100.0f; ro *= (float) goom_irand (info->gRandom, 100) / 100.0f + 1.0f; theta = goom_irand (info->gRandom, 256); fs->stars[i].vx = ro * cos256[theta]; fs->stars[i].vy = -0.2f + ro * sin256[theta]; fs->stars[i].ax = 0; fs->stars[i].ay = gravity; fs->stars[i].age = 0; if (vage < fs->min_age) vage = fs->min_age; fs->stars[i].vage = vage; } /** * Met a jour la position et vitesse d'une particule. */ static void updateStar (Star * s) { s->x += s->vx; s->y += s->vy; s->vx += s->ax; s->vy += s->ay; s->age += s->vage; } /** * Ajoute de nouvelles particules au moment d'un evenement sonore. */ static void fs_sound_event_occured (VisualFX * _this, PluginInfo * info) { FSData *data = (FSData *) _this->fx_data; int i; int max = (int) ((1.0f + info->sound.goomPower) * goom_irand (info->gRandom, 150)) + 100; float radius = (1.0f + info->sound.goomPower) * (float) (goom_irand (info->gRandom, 150) + 50) / 300; int mx; int my; float vage, gravity = 0.02f; switch (data->fx_mode) { case FIREWORKS_FX: { double dx, dy; do { mx = goom_irand (info->gRandom, info->screen.width); my = goom_irand (info->gRandom, info->screen.height); dx = (mx - info->screen.width / 2); dy = (my - info->screen.height / 2); } while (dx * dx + dy * dy < (info->screen.height / 2) * (info->screen.height / 2)); vage = data->max_age * (1.0f - info->sound.goomPower); } break; case RAIN_FX: mx = goom_irand (info->gRandom, info->screen.width); if (mx > info->screen.width / 2) mx = info->screen.width; else mx = 0; my = -(info->screen.height / 3) - goom_irand (info->gRandom, info->screen.width / 3); radius *= 1.5; vage = 0.002f; break; case FOUNTAIN_FX: my = info->screen.height + 2; vage = 0.001f; radius += 1.0f; mx = info->screen.width / 2; gravity = 0.04f; break; default: return; /* my = i R A N D (info->screen.height); vage = 0.01f; */ } radius *= info->screen.height / 200.0f; /* why 200 ? because the FX was developped on 320x200 */ max *= info->screen.height / 200.0f; if (info->sound.timeSinceLastBigGoom < 1) { radius *= 1.5; max *= 2; } for (i = 0; i < max; ++i) addABomb (data, mx, my, radius, vage, gravity, info); } /** * Main methode of the FX. */ static void fs_apply (VisualFX * _this, Pixel * src, Pixel * dest, PluginInfo * info) { int i; int col; FSData *data = (FSData *) _this->fx_data; /* Get the new parameters values */ data->min_age = 1.0f - (float) IVAL (data->min_age_p) / 100.0f; data->max_age = 1.0f - (float) IVAL (data->max_age_p) / 100.0f; FVAL (data->nbStars_p) = (float) data->nbStars / (float) data->maxStars; data->nbStars_p.change_listener (&data->nbStars_p); data->maxStars = IVAL (data->nbStars_limit_p); data->fx_mode = IVAL (data->fx_mode_p); /* look for events */ if (info->sound.timeSinceLastGoom < 1) { fs_sound_event_occured (_this, info); if (goom_irand (info->gRandom, 20) == 1) { IVAL (data->fx_mode_p) = goom_irand (info->gRandom, (LAST_FX * 3)); data->fx_mode_p.change_listener (&data->fx_mode_p); } } /* update particules */ for (i = 0; i < data->nbStars; ++i) { updateStar (&data->stars[i]); /* dead particule */ if (data->stars[i].age >= NCOL) continue; /* choose the color of the particule */ col = colval[(int) data->stars[i].age]; /* draws the particule */ info->methods.draw_line (dest, (int) data->stars[i].x, (int) data->stars[i].y, (int) (data->stars[i].x - data->stars[i].vx * 6), (int) (data->stars[i].y - data->stars[i].vy * 6), col, (int) info->screen.width, (int) info->screen.height); info->methods.draw_line (dest, (int) data->stars[i].x, (int) data->stars[i].y, (int) (data->stars[i].x - data->stars[i].vx * 2), (int) (data->stars[i].y - data->stars[i].vy * 2), col, (int) info->screen.width, (int) info->screen.height); } /* look for dead particules */ for (i = 0; i < data->nbStars;) { if ((data->stars[i].x > info->screen.width + 64) || ((data->stars[i].vy >= 0) && (data->stars[i].y - 16 * data->stars[i].vy > info->screen.height)) || (data->stars[i].x < -64) || (data->stars[i].age >= NCOL)) { data->stars[i] = data->stars[data->nbStars - 1]; data->nbStars--; } else ++i; } } VisualFX flying_star_create (void) { VisualFX vfx = { fs_init, fs_free, fs_apply, NULL }; return vfx; }