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