790649d56fd8d16686b69307251465741256022d
[platform/upstream/gst-plugins-good.git] / gst / effectv / gstshagadelic.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * EffecTV:
5  * Copyright (C) 2001 FUKUCHI Kentarou
6  *
7  * Inspired by Adrian Likin's script for the GIMP.
8  * EffecTV is free software.  This library is free software;
9  * you can redistribute it and/or
10  *  modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */ 
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 #include <math.h>
29 #include <string.h>
30 #include <gst/gst.h>
31 #include <gstvideofilter.h>
32
33 #define GST_TYPE_SHAGADELICTV \
34   (gst_shagadelictv_get_type())
35 #define GST_SHAGADELICTV(obj) \
36   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SHAGADELICTV,GstShagadelicTV))
37 #define GST_SHAGADELICTV_CLASS(klass) \
38   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SHAGADELICTV,GstShagadelicTVClass))
39 #define GST_IS_SHAGADELICTV(obj) \
40   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SHAGADELICTV))
41 #define GST_IS_SHAGADELICTV_CLASS(obj) \
42   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SHAGADELICTV))
43
44 typedef struct _GstShagadelicTV GstShagadelicTV;
45 typedef struct _GstShagadelicTVClass GstShagadelicTVClass;
46
47 struct _GstShagadelicTV
48 {
49   GstVideofilter videofilter;
50
51   gint width, height;
52   gint stat;
53   gchar *ripple;
54   gchar *spiral;
55   guchar phase;
56   gint rx, ry;
57   gint bx, by;
58   gint rvx, rvy;
59   gint bvx, bvy;
60 };
61
62 struct _GstShagadelicTVClass
63 {
64   GstVideofilterClass parent_class;
65 };
66
67 /* Filter signals and args */
68 enum
69 {
70   /* FILL ME */
71   LAST_SIGNAL
72 };
73
74 enum
75 {
76   ARG_0,
77 };
78
79 static void     gst_shagadelictv_base_init      (gpointer g_class);
80 static void     gst_shagadelictv_class_init     (gpointer g_class, gpointer class_data);
81 static void     gst_shagadelictv_init           (GTypeInstance *instance, gpointer g_class);
82
83 static void     gst_shagadelic_initialize       (GstShagadelicTV *filter);
84
85 static void     gst_shagadelictv_set_property   (GObject * object, guint prop_id,
86                                                  const GValue * value, GParamSpec * pspec);
87 static void     gst_shagadelictv_get_property   (GObject * object, guint prop_id,
88                                                  GValue * value, GParamSpec * pspec);
89 static void     gst_shagadelictv_setup          (GstVideofilter *videofilter);
90 static void     gst_shagadelictv_rgb32          (GstVideofilter *videofilter, void *d, void *s);
91
92 /*static guint gst_shagadelictv_signals[LAST_SIGNAL] = { 0 }; */
93
94 GType gst_shagadelictv_get_type (void)
95 {
96   static GType shagadelictv_type = 0;
97
98   if (!shagadelictv_type) {
99     static const GTypeInfo shagadelictv_info = {
100       sizeof (GstShagadelicTVClass), 
101       gst_shagadelictv_base_init,
102       NULL,
103       (GClassInitFunc) gst_shagadelictv_class_init,
104       NULL,
105       NULL,
106       sizeof (GstShagadelicTV),
107       0,
108       (GInstanceInitFunc) gst_shagadelictv_init,
109     };
110
111     shagadelictv_type = g_type_register_static (GST_TYPE_VIDEOFILTER, "GstShagadelicTV", &shagadelictv_info, 0);
112   }
113   return shagadelictv_type;
114 }
115
116 static GstVideofilterFormat gst_shagadelictv_formats[] = {
117   { "RGB ", 32, gst_shagadelictv_rgb32, 24, G_BIG_ENDIAN, 0x0000ff00, 0x00ff0000, 0xff000000 }
118 };
119   
120 static void
121 gst_shagadelictv_base_init (gpointer g_class)
122 {
123   /* elementfactory information */
124   static GstElementDetails gst_shagadelictv_details = GST_ELEMENT_DETAILS (
125     "ShagadelicTV",
126     "Filter/Effect/Video",
127     "Oh behave, ShagedelicTV makes images shagadelic!",
128     "Wim Taymans <wim.taymans@chello.be>"
129   );
130
131   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
132   GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
133   int i;
134   
135   gst_element_class_set_details (element_class, &gst_shagadelictv_details);
136
137   for(i=0;i<G_N_ELEMENTS(gst_shagadelictv_formats);i++){
138     gst_videofilter_class_add_format(videofilter_class,
139         gst_shagadelictv_formats + i);
140   }
141
142   gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
143 }
144
145 static void
146 gst_shagadelictv_class_init (gpointer g_class, gpointer class_data)
147 {
148   GObjectClass *gobject_class;
149   GstVideofilterClass *videofilter_class;
150
151   gobject_class = G_OBJECT_CLASS (g_class);
152   videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
153
154   gobject_class->set_property = gst_shagadelictv_set_property;
155   gobject_class->get_property = gst_shagadelictv_get_property;
156
157   videofilter_class->setup = gst_shagadelictv_setup;
158 }
159
160 static void
161 gst_shagadelictv_init (GTypeInstance *instance, gpointer g_class)
162 {
163   GstShagadelicTV *filter = GST_SHAGADELICTV (instance);
164
165   filter->ripple = NULL;
166   filter->spiral = NULL;
167 }
168
169 static void 
170 gst_shagadelictv_setup(GstVideofilter *videofilter)
171 {
172   GstShagadelicTV *filter;
173   int width = gst_videofilter_get_input_width(videofilter);
174   int height = gst_videofilter_get_input_height(videofilter);
175   int area;
176
177   g_return_if_fail (GST_IS_SHAGADELICTV (videofilter));
178   filter = GST_SHAGADELICTV (videofilter);
179
180   filter->width = width;
181   filter->height = height;
182
183   area = filter->width * filter->height;
184
185   g_free (filter->ripple);
186   g_free (filter->spiral);
187
188   filter->ripple = (gchar *) g_malloc (area * 4);
189   filter->spiral = (gchar *) g_malloc (area);
190
191   gst_shagadelic_initialize (filter);
192 }
193
194 static unsigned int
195 fastrand (void)
196 {   
197   static unsigned int fastrand_val;
198
199   return (fastrand_val = fastrand_val * 1103515245 + 12345);
200 }
201
202 static void
203 gst_shagadelic_initialize (GstShagadelicTV *filter)
204 {
205   int i, x, y;
206 #ifdef PS2
207   float xx, yy;
208 #else
209   double xx, yy;
210 #endif
211
212   i = 0;
213   for(y = 0; y < filter->height * 2; y++) {
214     yy = y - filter->height;
215     yy *= yy;
216
217     for (x = 0; x < filter->width * 2; x++) {
218       xx = x - filter->width;
219 #ifdef PS2
220       filter->ripple[i++] = ((unsigned int)(sqrtf(xx*xx+yy)*8))&255;
221 #else
222       filter->ripple[i++] = ((unsigned int)(sqrt(xx*xx+yy)*8))&255;
223 #endif
224     }
225   }
226
227   i = 0;
228   for (y = 0; y < filter->height; y++) {
229     yy = y - filter->height/2;
230     
231     for (x = 0; x < filter->width; x++) {
232       xx = x - filter->width/2;
233 #ifdef PS2
234       filter->spiral[i++] = ((unsigned int)
235         ((atan2f(xx, yy)/((float)M_PI)*256*9) + (sqrtf(xx*xx+yy*yy)*5)))&255;
236 #else
237       filter->spiral[i++] = ((unsigned int)
238         ((atan2(xx, yy)/M_PI*256*9) + (sqrt(xx*xx+yy*yy)*5)))&255;
239 #endif
240 /* Here is another Swinger!
241  * ((atan2(xx, yy)/M_PI*256) + (sqrt(xx*xx+yy*yy)*10))&255;
242  */
243     }
244   }
245   filter->rx = fastrand () % filter->width;
246   filter->ry = fastrand () % filter->height;
247   filter->bx = fastrand () % filter->width;
248   filter->by = fastrand () % filter->height;
249   filter->rvx = -2;
250   filter->rvy = -2;
251   filter->bvx = 2;
252   filter->bvy = 2;
253   filter->phase = 0;
254 }
255
256 static void
257 gst_shagadelictv_rgb32 (GstVideofilter *videofilter, void *d, void *s)
258 {
259   GstShagadelicTV *filter;
260   guint32 *src, *dest;
261   gint x, y;
262   guint32 v;
263   guchar r, g, b;
264   gint width, height;
265
266   filter = GST_SHAGADELICTV (videofilter);
267
268   src = (guint32 *) s;
269   dest = (guint32 *) d;
270
271   width = filter->width;
272   height = filter->height;
273
274   for (y = 0; y < height; y++) {
275     for (x = 0; x < width; x++) {
276       v = *src++ | 0x1010100;
277       v = (v - 0x707060) & 0x1010100;
278       v -= v >> 8;
279 /* Try another Babe! 
280  * v = *src++;
281  * *dest++ = v & ((r<<16)|(g<<8)|b);
282  */
283       r = (gchar) (filter->ripple[(filter->ry + y) * width * 2 + filter->rx + x] + filter->phase * 2) >> 7;
284       g = (gchar) (filter->spiral[y * width + x] + filter->phase * 3) >> 7;
285       b = (gchar) (filter->ripple[(filter->by + y) * width * 2 + filter->bx + x] - filter->phase) >> 7;
286       *dest++ = v & ((r << 16) | (g << 8) | b);
287     }
288   }
289
290   filter->phase -= 8;
291   if ((filter->rx + filter->rvx) < 0 || (filter->rx + filter->rvx) >= width)  filter->rvx =- filter->rvx;
292   if ((filter->ry + filter->rvy) < 0 || (filter->ry + filter->rvy) >= height) filter->rvy =- filter->rvy;
293   if ((filter->bx + filter->bvx) < 0 || (filter->bx + filter->bvx) >= width)  filter->bvx =- filter->bvx;
294   if ((filter->by + filter->bvy) < 0 || (filter->by + filter->bvy) >= height) filter->bvy =- filter->bvy;
295   filter->rx += filter->rvx;
296   filter->ry += filter->rvy;
297   filter->bx += filter->bvx;
298   filter->by += filter->bvy;
299 }
300
301 static void
302 gst_shagadelictv_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
303 {
304   GstShagadelicTV *filter;
305
306   /* it's not null if we got it, but it might not be ours */
307   g_return_if_fail (GST_IS_SHAGADELICTV (object));
308
309   filter = GST_SHAGADELICTV (object);
310
311   switch (prop_id) {
312     default:
313       break;
314   }
315 }
316
317 static void
318 gst_shagadelictv_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
319 {
320   GstShagadelicTV *filter;
321
322   /* it's not null if we got it, but it might not be ours */
323   g_return_if_fail (GST_IS_SHAGADELICTV (object));
324
325   filter = GST_SHAGADELICTV (object);
326
327   switch (prop_id) {
328     default:
329       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
330       break;
331   }
332 }