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