ba2d1d6c08cc2734e85b6095ed08e8119743a079
[platform/upstream/gst-plugins-good.git] / gst / effectv / gstdice.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * dice.c: a 'dicing' effect
5  *  copyright (c) 2001 Sam Mertens.  This code is subject to the provisions of
6  *  the GNU Library Public License.
7  *
8  * I suppose this looks similar to PuzzleTV, but it's not. The screen is
9  * divided into small squares, each of which is rotated either 0, 90, 180 or
10  * 270 degrees.  The amount of rotation for each square is chosen at random.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 #include "config.h"
15 #endif
16 #include <string.h>
17 #include <gst/gst.h>
18 #include <gstvideofilter.h>
19
20 #define GST_TYPE_DICETV \
21   (gst_dicetv_get_type())
22 #define GST_DICETV(obj) \
23   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DICETV,GstDiceTV))
24 #define GST_DICETV_CLASS(klass) \
25   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DICETV,GstDiceTVClass))
26 #define GST_IS_DICETV(obj) \
27   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DICETV))
28 #define GST_IS_DICETV_CLASS(obj) \
29   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DICETV))
30
31 typedef struct _GstDiceTV GstDiceTV;
32 typedef struct _GstDiceTVClass GstDiceTVClass;
33
34 #define DEFAULT_CUBE_BITS   4
35 #define MAX_CUBE_BITS       5
36 #define MIN_CUBE_BITS       0
37
38 typedef enum _dice_dir 
39 {
40   DICE_UP       = 0,
41   DICE_RIGHT    = 1,
42   DICE_DOWN     = 2,
43   DICE_LEFT     = 3
44 } DiceDir;
45
46 struct _GstDiceTV
47 {
48   GstVideofilter videofilter;
49
50   gint width, height;
51   gchar* dicemap;
52
53   gint g_cube_bits;
54   gint g_cube_size;
55   gint g_map_height;
56   gint g_map_width;
57 };
58
59 struct _GstDiceTVClass
60 {
61   GstVideofilterClass parent_class;
62
63   void (*reset) (GstElement *element);
64 };
65
66 /* Filter signals and args */
67 enum
68 {
69   /* FILL ME */
70   RESET_SIGNAL,
71   LAST_SIGNAL
72 };
73
74 enum
75 {
76   ARG_0,
77   ARG_CUBE_BITS,
78 };
79
80 static void     gst_dicetv_base_init            (gpointer g_class);
81 static void     gst_dicetv_class_init           (gpointer g_class, gpointer class_data);
82 static void     gst_dicetv_init                 (GTypeInstance *instance, gpointer g_class);
83
84 static void     gst_dicetv_reset_handler        (GstElement *elem);
85 static void     gst_dicetv_create_map           (GstDiceTV *filter);
86
87 static void     gst_dicetv_set_property         (GObject * object, guint prop_id,
88                                                  const GValue * value, GParamSpec * pspec);
89 static void     gst_dicetv_get_property         (GObject * object, guint prop_id,
90                                                  GValue * value, GParamSpec * pspec);
91 static void     gst_dicetv_setup                (GstVideofilter *videofilter);
92 static void     gst_dicetv_draw                 (GstVideofilter *videofilter, void *d, void *s);
93
94 static guint gst_dicetv_signals[LAST_SIGNAL] = { 0 };
95
96 GType gst_dicetv_get_type (void)
97 {
98   static GType dicetv_type = 0;
99
100   if (!dicetv_type) {
101     static const GTypeInfo dicetv_info = {
102       sizeof (GstDiceTVClass), 
103       gst_dicetv_base_init,
104       NULL,
105       (GClassInitFunc) gst_dicetv_class_init,
106       NULL,
107       NULL,
108       sizeof (GstDiceTV),
109       0,
110       (GInstanceInitFunc) gst_dicetv_init,
111     };
112
113     dicetv_type = g_type_register_static (GST_TYPE_VIDEOFILTER, "GstDiceTV", &dicetv_info, 0);
114   }
115   return dicetv_type;
116 }
117
118 static GstVideofilterFormat gst_dicetv_formats[] = {
119   { "RGB ", 32, gst_dicetv_draw, 24, G_BIG_ENDIAN, 0x00ff0000, 0x0000ff00, 0x000000ff },
120   { "RGB ", 32, gst_dicetv_draw, 24, G_BIG_ENDIAN, 0xff000000, 0x00ff0000, 0x0000ff00 },
121   { "RGB ", 32, gst_dicetv_draw, 24, G_BIG_ENDIAN, 0x000000ff, 0x0000ff00, 0x00ff0000 },
122   { "RGB ", 32, gst_dicetv_draw, 24, G_BIG_ENDIAN, 0x0000ff00, 0x00ff0000, 0xff000000 },
123 };
124
125 static void
126 gst_dicetv_base_init (gpointer g_class)
127 {
128   /* elementfactory information */
129   static GstElementDetails gst_dicetv_details = GST_ELEMENT_DETAILS (
130     "DiceTV",
131     "Filter/Effect/Video",
132     "'Dices' the screen up into many small squares",
133     "Wim Taymans <wim.taymans@chello.be>"
134   );
135
136   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
137   GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
138   int i;
139   
140   gst_element_class_set_details (element_class, &gst_dicetv_details);
141
142   for(i=0; i < G_N_ELEMENTS(gst_dicetv_formats); i++) {
143     gst_videofilter_class_add_format(videofilter_class,
144         gst_dicetv_formats + i);
145   }
146
147   gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
148 }
149
150 static void
151 gst_dicetv_class_init (gpointer g_class, gpointer class_data)
152 {
153   GObjectClass *gobject_class;
154   GstVideofilterClass *videofilter_class;
155   GstDiceTVClass *dicetv_class;
156
157   gobject_class = G_OBJECT_CLASS (g_class);
158   videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
159   dicetv_class = GST_DICETV_CLASS (g_class);
160
161   gst_dicetv_signals[RESET_SIGNAL] =
162     g_signal_new ("reset",
163                   G_TYPE_FROM_CLASS (g_class),
164                   G_SIGNAL_RUN_LAST,
165                   G_STRUCT_OFFSET (GstDiceTVClass, reset),
166                   NULL, NULL,
167                   g_cclosure_marshal_VOID__VOID,
168                   G_TYPE_NONE, 0);
169
170   dicetv_class->reset = gst_dicetv_reset_handler;
171         
172   g_object_class_install_property (gobject_class, ARG_CUBE_BITS,
173     g_param_spec_int ("square_bits","Square Bits","The size of the Squares",
174                       MIN_CUBE_BITS, MAX_CUBE_BITS, DEFAULT_CUBE_BITS, G_PARAM_READWRITE));
175
176   gobject_class->set_property = gst_dicetv_set_property;
177   gobject_class->get_property = gst_dicetv_get_property;
178
179   videofilter_class->setup = gst_dicetv_setup;
180 }
181
182 static void
183 gst_dicetv_setup (GstVideofilter *videofilter)
184 {
185   GstDiceTV *dicetv;
186
187   g_return_if_fail (GST_IS_DICETV (videofilter));
188   dicetv = GST_DICETV (videofilter);
189
190   dicetv->width = gst_videofilter_get_input_width (videofilter);
191   dicetv->height = gst_videofilter_get_input_height (videofilter);
192
193   g_free (dicetv->dicemap);
194   dicetv->dicemap = (gchar *) g_malloc (dicetv->height * dicetv->width * sizeof(char));
195   gst_dicetv_create_map (dicetv);
196 }
197
198 static void
199 gst_dicetv_init (GTypeInstance *instance, gpointer g_class)
200 {
201   GstDiceTV *filter = GST_DICETV (instance);
202
203   filter->dicemap = NULL;
204   filter->g_cube_bits = DEFAULT_CUBE_BITS;
205   filter->g_cube_size = 0;
206   filter->g_map_height = 0;
207   filter->g_map_width = 0;
208 }
209
210 static void
211 gst_dicetv_reset_handler (GstElement *element)
212 {
213   GstDiceTV *filter = GST_DICETV (element);
214
215   gst_dicetv_create_map (filter);
216 }
217
218 static unsigned int
219 fastrand (void)
220 {   
221   static unsigned int fastrand_val;
222
223   return (fastrand_val = fastrand_val * 1103515245 + 12345);
224 }
225
226 static void 
227 gst_dicetv_draw (GstVideofilter *videofilter, void *d, void *s)
228 {
229   GstDiceTV *filter;
230   guint32 *src;
231   guint32 *dest;
232   gint i;
233   gint map_x, map_y, map_i;
234   gint base;
235   gint dx, dy, di;
236   gint video_width = filter->width;
237   gint g_cube_bits = filter->g_cube_bits;
238   gint g_cube_size = filter->g_cube_size;
239     
240   filter = GST_DICETV (videofilter);
241   src = (guint32 *)s;
242   dest = (guint32 *)d;
243
244   video_width = filter->width;
245   g_cube_bits = filter->g_cube_bits;
246   g_cube_size = filter->g_cube_size;
247
248   map_i = 0;
249   for (map_y = 0; map_y < filter->g_map_height; map_y++) {
250     for (map_x = 0; map_x < filter->g_map_width; map_x++) {
251        base = (map_y << g_cube_bits) * video_width + (map_x << g_cube_bits);
252
253        switch (filter->dicemap[map_i]) {
254          case DICE_UP:
255            for (dy = 0; dy < g_cube_size; dy++) {
256              i = base + dy * video_width;
257              for (dx = 0; dx < g_cube_size; dx++) {
258                dest[i] = src[i];
259                i++;
260              }
261            }
262            break;
263          case DICE_LEFT:
264            for (dy = 0; dy < g_cube_size; dy++) {
265              i = base + dy * video_width;
266
267              for (dx = 0; dx < g_cube_size; dx++) {
268                di = base + (dx * video_width) + (g_cube_size - dy - 1);
269                dest[di] = src[i];
270                i++;
271              }
272            }
273            break;
274          case DICE_DOWN:
275            for (dy = 0; dy < g_cube_size; dy++) {
276              di = base + dy * video_width;
277              i = base + (g_cube_size - dy - 1) * video_width + g_cube_size;
278              for (dx = 0; dx < g_cube_size; dx++) {
279                i--;
280                dest[di] = src[i];
281                di++;
282              }
283            }
284            break;
285          case DICE_RIGHT:
286            for (dy = 0; dy < g_cube_size; dy++) {
287              i = base + (dy * video_width);
288              for (dx = 0; dx < g_cube_size; dx++) {
289                di = base + dy + (g_cube_size - dx - 1) * video_width;
290                dest[di] = src[i];
291                i++;
292              }
293            }
294            break;
295          default:
296            g_assert_not_reached ();
297            break;
298       }
299       map_i++;
300     }
301   }
302 }
303
304 static void 
305 gst_dicetv_create_map (GstDiceTV *filter)
306 {
307   gint x, y, i;
308     
309   filter->g_map_height = filter->height >> filter->g_cube_bits;
310   filter->g_map_width = filter->width >> filter->g_cube_bits;
311   filter->g_cube_size = 1 << filter->g_cube_bits;
312
313   i = 0;
314
315   for (y = 0; y < filter->g_map_height; y++) {
316     for(x = 0; x < filter->g_map_width; x++) {
317       // dicemap[i] = ((i + y) & 0x3); /* Up, Down, Left or Right */
318       filter->dicemap[i] = (fastrand() >> 24) & 0x03;
319       i++;
320     }
321   }
322 }
323
324 static void
325 gst_dicetv_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
326 {
327   GstDiceTV *filter;
328
329   /* it's not null if we got it, but it might not be ours */
330   g_return_if_fail (GST_IS_DICETV (object));
331
332   filter = GST_DICETV (object);
333
334   switch (prop_id) {
335     case ARG_CUBE_BITS:
336       filter->g_cube_bits = g_value_get_int (value);
337       gst_dicetv_create_map (filter);
338     default:
339       break;
340   }
341 }
342
343 static void
344 gst_dicetv_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
345 {
346   GstDiceTV *filter;
347
348   /* it's not null if we got it, but it might not be ours */
349   g_return_if_fail (GST_IS_DICETV (object));
350
351   filter = GST_DICETV (object);
352
353   switch (prop_id) {
354     case ARG_CUBE_BITS:
355       g_value_set_int (value, filter->g_cube_bits);
356       break;
357     default:
358       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
359       break;
360   }
361 }