9906c053bb7a0dcae9e85dce44c58bb76843c2d4
[platform/upstream/gst-plugins-good.git] / gst / goom / flying_stars_fx.c
1 #include "goom_fx.h"
2 #include "goom_plugin_info.h"
3 #include "goom_tools.h"
4
5 #include "mathtools.h"
6
7 /* TODO:-- FAIRE PROPREMENT... BOAH... */
8 #define NCOL 15
9
10 /*static const int colval[] = {
11 0xfdf6f5,
12 0xfae4e4,
13 0xf7d1d1,
14 0xf3b6b5,
15 0xefa2a2,
16 0xec9190,
17 0xea8282,
18 0xe87575,
19 0xe46060,
20 0xe14b4c,
21 0xde3b3b,
22 0xdc2d2f,
23 0xd92726,
24 0xd81619,
25 0xd50c09,
26 0
27 };
28 */
29 static const int colval[] = {
30   0x1416181a,
31   0x1419181a,
32   0x141f181a,
33   0x1426181a,
34   0x142a181a,
35   0x142f181a,
36   0x1436181a,
37   0x142f1819,
38   0x14261615,
39   0x13201411,
40   0x111a100a,
41   0x0c180508,
42   0x08100304,
43   0x00050101,
44   0x0
45 };
46
47
48 /* The different modes of the visual FX.
49  * Put this values on fx_mode */
50 #define FIREWORKS_FX 0
51 #define RAIN_FX 1
52 #define FOUNTAIN_FX 2
53 #define LAST_FX 3
54
55 typedef struct _FS_STAR
56 {
57   float x, y;
58   float vx, vy;
59   float ax, ay;
60   float age, vage;
61 } Star;
62
63 typedef struct _FS_DATA
64 {
65
66   int fx_mode;
67   int nbStars;
68
69   int maxStars;
70   Star *stars;
71
72   float min_age;
73   float max_age;
74
75   PluginParam min_age_p;
76   PluginParam max_age_p;
77   PluginParam nbStars_p;
78   PluginParam nbStars_limit_p;
79   PluginParam fx_mode_p;
80
81   PluginParameters params;
82 } FSData;
83
84 static void
85 fs_init (VisualFX * _this, PluginInfo * info)
86 {
87
88   FSData *data;
89
90   data = (FSData *) malloc (sizeof (FSData));
91
92   data->fx_mode = FIREWORKS_FX;
93   data->maxStars = 4096;
94   data->stars = (Star *) malloc (data->maxStars * sizeof (Star));
95   data->nbStars = 0;
96
97   data->max_age_p = secure_i_param ("Fireworks Smallest Bombs");
98   IVAL (data->max_age_p) = 80;
99   IMIN (data->max_age_p) = 0;
100   IMAX (data->max_age_p) = 100;
101   ISTEP (data->max_age_p) = 1;
102
103   data->min_age_p = secure_i_param ("Fireworks Largest Bombs");
104   IVAL (data->min_age_p) = 99;
105   IMIN (data->min_age_p) = 0;
106   IMAX (data->min_age_p) = 100;
107   ISTEP (data->min_age_p) = 1;
108
109   data->nbStars_limit_p = secure_i_param ("Max Number of Particules");
110   IVAL (data->nbStars_limit_p) = 512;
111   IMIN (data->nbStars_limit_p) = 0;
112   IMAX (data->nbStars_limit_p) = data->maxStars;
113   ISTEP (data->nbStars_limit_p) = 64;
114
115   data->fx_mode_p = secure_i_param ("FX Mode");
116   IVAL (data->fx_mode_p) = data->fx_mode;
117   IMIN (data->fx_mode_p) = 1;
118   IMAX (data->fx_mode_p) = 3;
119   ISTEP (data->fx_mode_p) = 1;
120
121   data->nbStars_p = secure_f_feedback ("Number of Particules (% of Max)");
122
123   data->params = plugin_parameters ("Particule System", 7);
124   data->params.params[0] = &data->fx_mode_p;
125   data->params.params[1] = &data->nbStars_limit_p;
126   data->params.params[2] = 0;
127   data->params.params[3] = &data->min_age_p;
128   data->params.params[4] = &data->max_age_p;
129   data->params.params[5] = 0;
130   data->params.params[6] = &data->nbStars_p;
131
132   _this->params = &data->params;
133   _this->fx_data = (void *) data;
134 }
135
136 static void
137 fs_free (VisualFX * _this)
138 {
139   FSData *data = (FSData *) _this->fx_data;
140
141   goom_plugin_parameters_free (&data->params);
142
143   free (data->stars);
144   free (_this->fx_data);
145 }
146
147
148 /**
149  * Cree une nouvelle 'bombe', c'est a dire une particule appartenant a une fusee d'artifice.
150  */
151 static void
152 addABomb (FSData * fs, int mx, int my, float radius, float vage, float gravity,
153     PluginInfo * info)
154 {
155
156   int i = fs->nbStars;
157   float ro;
158   int theta;
159
160   if (fs->nbStars >= fs->maxStars)
161     return;
162   fs->nbStars++;
163
164   fs->stars[i].x = mx;
165   fs->stars[i].y = my;
166
167   ro = radius * (float) goom_irand (info->gRandom, 100) / 100.0f;
168   ro *= (float) goom_irand (info->gRandom, 100) / 100.0f + 1.0f;
169   theta = goom_irand (info->gRandom, 256);
170
171   fs->stars[i].vx = ro * cos256[theta];
172   fs->stars[i].vy = -0.2f + ro * sin256[theta];
173
174   fs->stars[i].ax = 0;
175   fs->stars[i].ay = gravity;
176
177   fs->stars[i].age = 0;
178   if (vage < fs->min_age)
179     vage = fs->min_age;
180   fs->stars[i].vage = vage;
181 }
182
183
184 /**
185  * Met a jour la position et vitesse d'une particule.
186  */
187 static void
188 updateStar (Star * s)
189 {
190   s->x += s->vx;
191   s->y += s->vy;
192   s->vx += s->ax;
193   s->vy += s->ay;
194   s->age += s->vage;
195 }
196
197
198 /**
199  * Ajoute de nouvelles particules au moment d'un evenement sonore.
200  */
201 static void
202 fs_sound_event_occured (VisualFX * _this, PluginInfo * info)
203 {
204
205   FSData *data = (FSData *) _this->fx_data;
206   int i;
207
208   int max = (int) ((1.0f + info->sound.goomPower) * goom_irand (info->gRandom,
209           150)) + 100;
210   float radius =
211       (1.0f + info->sound.goomPower) * (float) (goom_irand (info->gRandom,
212           150) + 50) / 300;
213   int mx;
214   int my;
215   float vage, gravity = 0.02f;
216
217   switch (data->fx_mode) {
218     case FIREWORKS_FX:
219     {
220       double dx, dy;
221
222       do {
223         mx = goom_irand (info->gRandom, info->screen.width);
224         my = goom_irand (info->gRandom, info->screen.height);
225         dx = (mx - info->screen.width / 2);
226         dy = (my - info->screen.height / 2);
227       } while (dx * dx + dy * dy <
228           (info->screen.height / 2) * (info->screen.height / 2));
229       vage = data->max_age * (1.0f - info->sound.goomPower);
230     }
231       break;
232     case RAIN_FX:
233       mx = goom_irand (info->gRandom, info->screen.width);
234       if (mx > info->screen.width / 2)
235         mx = info->screen.width;
236       else
237         mx = 0;
238       my = -(info->screen.height / 3) - goom_irand (info->gRandom,
239           info->screen.width / 3);
240       radius *= 1.5;
241       vage = 0.002f;
242       break;
243     case FOUNTAIN_FX:
244       my = info->screen.height + 2;
245       vage = 0.001f;
246       radius += 1.0f;
247       mx = info->screen.width / 2;
248       gravity = 0.04f;
249       break;
250     default:
251       return;
252       /* my = i R A N D (info->screen.height); vage = 0.01f; */
253   }
254
255   radius *= info->screen.height / 200.0f;       /* why 200 ? because the FX was developped on 320x200 */
256   max *= info->screen.height / 200.0f;
257
258   if (info->sound.timeSinceLastBigGoom < 1) {
259     radius *= 1.5;
260     max *= 2;
261   }
262   for (i = 0; i < max; ++i)
263     addABomb (data, mx, my, radius, vage, gravity, info);
264 }
265
266
267 /**
268  * Main methode of the FX.
269  */
270 static void
271 fs_apply (VisualFX * _this, Pixel * src, Pixel * dest, PluginInfo * info)
272 {
273
274   int i;
275   int col;
276   FSData *data = (FSData *) _this->fx_data;
277
278   /* Get the new parameters values */
279   data->min_age = 1.0f - (float) IVAL (data->min_age_p) / 100.0f;
280   data->max_age = 1.0f - (float) IVAL (data->max_age_p) / 100.0f;
281   FVAL (data->nbStars_p) = (float) data->nbStars / (float) data->maxStars;
282   data->nbStars_p.change_listener (&data->nbStars_p);
283   data->maxStars = IVAL (data->nbStars_limit_p);
284   data->fx_mode = IVAL (data->fx_mode_p);
285
286   /* look for events */
287   if (info->sound.timeSinceLastGoom < 1) {
288     fs_sound_event_occured (_this, info);
289     if (goom_irand (info->gRandom, 20) == 1) {
290       IVAL (data->fx_mode_p) = goom_irand (info->gRandom, (LAST_FX * 3));
291       data->fx_mode_p.change_listener (&data->fx_mode_p);
292     }
293   }
294
295   /* update particules */
296   for (i = 0; i < data->nbStars; ++i) {
297     updateStar (&data->stars[i]);
298
299     /* dead particule */
300     if (data->stars[i].age >= NCOL)
301       continue;
302
303     /* choose the color of the particule */
304     col = colval[(int) data->stars[i].age];
305
306     /* draws the particule */
307     info->methods.draw_line (dest, (int) data->stars[i].x,
308         (int) data->stars[i].y,
309         (int) (data->stars[i].x - data->stars[i].vx * 6),
310         (int) (data->stars[i].y - data->stars[i].vy * 6), col,
311         (int) info->screen.width, (int) info->screen.height);
312     info->methods.draw_line (dest, (int) data->stars[i].x,
313         (int) data->stars[i].y,
314         (int) (data->stars[i].x - data->stars[i].vx * 2),
315         (int) (data->stars[i].y - data->stars[i].vy * 2), col,
316         (int) info->screen.width, (int) info->screen.height);
317   }
318
319   /* look for dead particules */
320   for (i = 0; i < data->nbStars;) {
321
322     if ((data->stars[i].x > info->screen.width + 64)
323         || ((data->stars[i].vy >= 0)
324             && (data->stars[i].y - 16 * data->stars[i].vy >
325                 info->screen.height))
326         || (data->stars[i].x < -64)
327         || (data->stars[i].age >= NCOL)) {
328       data->stars[i] = data->stars[data->nbStars - 1];
329       data->nbStars--;
330     } else
331       ++i;
332   }
333 }
334
335 VisualFX
336 flying_star_create (void)
337 {
338   VisualFX vfx = {
339     fs_init,
340     fs_free,
341     fs_apply,
342     NULL
343   };
344   return vfx;
345 }