| /* 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., 51 Franklin St, Fifth Floor, |
| * Boston, MA 02110-1301, 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; |
| |
| secure_i_param (&data->max_age_p, "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; |
| |
| secure_i_param (&data->min_age_p, "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; |
| |
| secure_i_param (&data->nbStars_limit_p, "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; |
| |
| secure_i_param (&data->fx_mode_p, "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; |
| |
| secure_f_feedback (&data->nbStars_p, "Number of Particules (% of Max)"); |
| |
| plugin_parameters (&data->params, "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; |
| } |
| } |
| |
| void |
| flying_star_create (VisualFX * vfx) |
| { |
| vfx->init = fs_init; |
| vfx->free = fs_free; |
| vfx->apply = fs_apply; |
| vfx->fx_data = NULL; |
| vfx->params = NULL; |
| } |