]> git.sesse.net Git - vlc/blob - modules/video_filter/puzzle.c
* motiondetect.c: remove useless include.
[vlc] / modules / video_filter / puzzle.c
1 /*****************************************************************************
2  * puzzle.c : Puzzle game
3  *****************************************************************************
4  * Copyright (C) 2005-2006 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program 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
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <string.h>
29
30 #include <vlc/vlc.h>
31 #include <vlc_vout.h>
32
33 #include <math.h>
34
35 #include "filter_common.h"
36 #include "vlc_image.h"
37 #include "vlc_input.h"
38 #include "vlc_playlist.h"
39
40 /*****************************************************************************
41  * Local prototypes
42  *****************************************************************************/
43 static int  Create    ( vlc_object_t * );
44 static void Destroy   ( vlc_object_t * );
45
46 static int  Init      ( vout_thread_t * );
47 static void End       ( vout_thread_t * );
48 static void Render    ( vout_thread_t *, picture_t * );
49
50 static int  SendEvents   ( vlc_object_t *, char const *,
51                            vlc_value_t, vlc_value_t, void * );
52 static int  MouseEvent   ( vlc_object_t *, char const *,
53                            vlc_value_t, vlc_value_t, void * );
54
55 static int PuzzleCallback( vlc_object_t *, char const *,
56                            vlc_value_t, vlc_value_t, void * );
57
58 /*****************************************************************************
59  * Module descriptor
60  *****************************************************************************/
61
62 #define ROWS_TEXT N_("Number of puzzle rows")
63 #define ROWS_LONGTEXT N_("Number of puzzle rows")
64 #define COLS_TEXT N_("Number of puzzle columns")
65 #define COLS_LONGTEXT N_("Number of puzzle columns")
66 #define BLACKSLOT_TEXT N_("Make one tile a black slot")
67 #define BLACKSLOT_LONGTEXT N_("Make one slot black. Other tiles can only be swapped with the black slot.")
68
69 #define CFG_PREFIX "puzzle-"
70
71 vlc_module_begin();
72     set_description( _("Puzzle interactive game video filter") );
73     set_shortname( _( "Puzzle" ));
74     set_capability( "video filter", 0 );
75     set_category( CAT_VIDEO );
76     set_subcategory( SUBCAT_VIDEO_VFILTER );
77
78     add_integer_with_range( CFG_PREFIX "rows", 4, 1, 128, NULL,
79                             ROWS_TEXT, ROWS_LONGTEXT, VLC_FALSE );
80     add_integer_with_range( CFG_PREFIX "cols", 4, 1, 128, NULL,
81                             COLS_TEXT, COLS_LONGTEXT, VLC_FALSE );
82     add_bool( CFG_PREFIX "black-slot", 0, NULL,
83               BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, VLC_FALSE );
84
85     set_callbacks( Create, Destroy );
86 vlc_module_end();
87
88 static const char *ppsz_filter_options[] = {
89     "rows", "cols", "black-slot", NULL
90 };
91
92 /*****************************************************************************
93  * vout_sys_t: Magnify video output method descriptor
94  *****************************************************************************/
95 struct vout_sys_t
96 {
97     vout_thread_t *p_vout;
98
99     image_handler_t *p_image;
100
101     int i_cols;
102     int i_rows;
103     int *pi_order;
104     int i_selected;
105     vlc_bool_t b_finished;
106
107     vlc_bool_t b_blackslot;
108 };
109
110 /*****************************************************************************
111  * Control: control facility for the vout (forwards to child vout)
112  *****************************************************************************/
113 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
114 {
115     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
116 }
117
118 /*****************************************************************************
119  * Misc stuff...
120  *****************************************************************************/
121 static vlc_bool_t finished( vout_sys_t *p_sys )
122 {
123     int i;
124     for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
125     {
126         if( i != p_sys->pi_order[i] ) return VLC_FALSE;
127     }
128     return VLC_TRUE;
129 }
130 static vlc_bool_t is_valid( vout_sys_t *p_sys )
131 {
132     int i, j, d=0;
133     if( p_sys->b_blackslot == VLC_FALSE ) return VLC_TRUE;
134     for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
135     {
136         if( p_sys->pi_order[i] == p_sys->i_cols * p_sys->i_rows - 1 )
137         {
138             d += i / p_sys->i_cols + 1;
139             continue;
140         }
141         for( j = i+1; j < p_sys->i_cols * p_sys->i_rows; j++ )
142         {
143             if( p_sys->pi_order[j] == p_sys->i_cols * p_sys->i_rows - 1 )
144                 continue;
145             if( p_sys->pi_order[i] > p_sys->pi_order[j] ) d++;
146         }
147     }
148     if( d%2!=0 ) return VLC_FALSE;
149     else return VLC_TRUE;
150 }
151 static void shuffle( vout_sys_t *p_sys )
152 {
153     int i, c;
154     free( p_sys->pi_order );
155     p_sys->pi_order = malloc( p_sys->i_cols * p_sys->i_rows * sizeof( int ) );
156     do
157     {
158         for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
159         {
160             p_sys->pi_order[i] = -1;
161         }
162         i = 0;
163         for( c = 0; c < p_sys->i_cols * p_sys->i_rows; )
164         {
165             i = rand()%( p_sys->i_cols * p_sys->i_rows );
166             if( p_sys->pi_order[i] == -1 )
167             {
168                 p_sys->pi_order[i] = c;
169                 c++;
170             }
171         }
172         p_sys->b_finished = finished( p_sys );
173     } while(    p_sys->b_finished == VLC_TRUE
174              || is_valid( p_sys ) == VLC_FALSE );
175
176     if( p_sys->b_blackslot == VLC_TRUE )
177     {
178         for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
179         {
180             if( p_sys->pi_order[i] ==
181                 p_sys->i_cols * p_sys->i_rows - 1 )
182             {
183                 p_sys->i_selected = i;
184                 break;
185             }
186         }
187     }
188     else
189     {
190         p_sys->i_selected = -1;
191     }
192 }
193
194 /*****************************************************************************
195  * Create: allocates Magnify video thread output method
196  *****************************************************************************/
197 static int Create( vlc_object_t *p_this )
198 {
199     vout_thread_t *p_vout = (vout_thread_t *)p_this;
200
201     /* Allocate structure */
202     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
203     if( p_vout->p_sys == NULL )
204     {
205         msg_Err( p_vout, "out of memory" );
206         return VLC_ENOMEM;
207     }
208
209     p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
210
211     config_ChainParse( p_vout, CFG_PREFIX, ppsz_filter_options,
212                        p_vout->p_cfg );
213
214     p_vout->p_sys->i_rows =
215         var_CreateGetIntegerCommand( p_vout, CFG_PREFIX "rows" );
216     p_vout->p_sys->i_cols =
217         var_CreateGetIntegerCommand( p_vout, CFG_PREFIX "cols" );
218     p_vout->p_sys->b_blackslot =
219         var_CreateGetBoolCommand( p_vout, CFG_PREFIX "black-slot" );
220     var_AddCallback( p_vout, CFG_PREFIX "rows",
221                      PuzzleCallback, p_vout->p_sys );
222     var_AddCallback( p_vout, CFG_PREFIX "cols",
223                      PuzzleCallback, p_vout->p_sys );
224     var_AddCallback( p_vout, CFG_PREFIX "black-slot",
225                      PuzzleCallback, p_vout->p_sys );
226
227     p_vout->p_sys->pi_order = NULL;
228     shuffle( p_vout->p_sys );
229
230     p_vout->pf_init = Init;
231     p_vout->pf_end = End;
232     p_vout->pf_manage = NULL;
233     p_vout->pf_render = Render;
234     p_vout->pf_display = NULL;
235     p_vout->pf_control = Control;
236
237     return VLC_SUCCESS;
238 }
239
240 /*****************************************************************************
241  * Init: initialize Magnify video thread output method
242  *****************************************************************************/
243 static int Init( vout_thread_t *p_vout )
244 {
245     int i_index;
246     picture_t *p_pic;
247     video_format_t fmt;
248     memset( &fmt, 0, sizeof( video_format_t ) );
249
250     I_OUTPUTPICTURES = 0;
251
252     /* Initialize the output structure */
253     p_vout->output.i_chroma = p_vout->render.i_chroma;
254     p_vout->output.i_width  = p_vout->render.i_width;
255     p_vout->output.i_height = p_vout->render.i_height;
256     p_vout->output.i_aspect = p_vout->render.i_aspect;
257
258     p_vout->fmt_out = p_vout->fmt_in;
259     fmt = p_vout->fmt_out;
260
261     /* Try to open the real video output */
262     msg_Dbg( p_vout, "spawning the real video output" );
263
264     p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
265
266     /* Everything failed */
267     if( p_vout->p_sys->p_vout == NULL )
268     {
269         msg_Err( p_vout, "cannot open vout, aborting" );
270         return VLC_EGENERIC;
271     }
272
273     var_AddCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout );
274     var_AddCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout );
275     var_AddCallback( p_vout->p_sys->p_vout, "mouse-clicked",
276                      MouseEvent, p_vout);
277
278     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
279     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
280     ADD_PARENT_CALLBACKS( SendEventsToChild );
281
282     return VLC_SUCCESS;
283 }
284
285 /*****************************************************************************
286  * End: terminate Magnify video thread output method
287  *****************************************************************************/
288 static void End( vout_thread_t *p_vout )
289 {
290     int i_index;
291
292     /* Free the fake output buffers we allocated */
293     for( i_index = I_OUTPUTPICTURES ; i_index ; )
294     {
295         i_index--;
296         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
297     }
298
299     var_DelCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout);
300     var_DelCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout);
301     var_DelCallback( p_vout->p_sys->p_vout, "mouse-clicked", MouseEvent, p_vout);
302 }
303
304 #define SHUFFLE_WIDTH 81
305 #define SHUFFLE_HEIGHT 13
306 static const char *shuffle_button[] =
307 {
308 ".................................................................................",
309 "..............  ............................   ........   ......  ...............",
310 "..............  ...........................  .........  ........  ...............",
311 "..............  ...........................  .........  ........  ...............",
312 "..     .......  .    .......  ....  ......     ......     ......  ........    ...",
313 ".  .... ......   ...  ......  ....  .......  .........  ........  .......  ..  ..",
314 ".  ...........  ....  ......  ....  .......  .........  ........  ......  ....  .",
315 ".      .......  ....  ......  ....  .......  .........  ........  ......        .",
316 "..      ......  ....  ......  ....  .......  .........  ........  ......  .......",
317 "......  ......  ....  ......  ....  .......  .........  ........  ......  .......",
318 ". ....  ......  ....  ......  ...   .......  .........  ........  .......  .... .",
319 "..     .......  ....  .......    .  .......  .........  ........  ........     ..",
320 "................................................................................."};
321
322
323 /*****************************************************************************
324  * Destroy: destroy Magnify video thread output method
325  *****************************************************************************/
326 static void Destroy( vlc_object_t *p_this )
327 {
328     vout_thread_t *p_vout = (vout_thread_t *)p_this;
329
330     if( p_vout->p_sys->p_vout )
331     {
332         DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
333         vlc_object_detach( p_vout->p_sys->p_vout );
334         vout_Destroy( p_vout->p_sys->p_vout );
335     }
336
337     image_HandlerDelete( p_vout->p_sys->p_image );
338     free( p_vout->p_sys->pi_order );
339
340     DEL_PARENT_CALLBACKS( SendEventsToChild );
341
342     free( p_vout->p_sys );
343 }
344
345 /*****************************************************************************
346  * Render: displays previously rendered output
347  *****************************************************************************/
348 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
349 {
350     picture_t *p_outpic;
351
352     //video_format_t fmt_out = {0};
353     //picture_t *p_converted;
354
355     int i_plane;
356
357     int i_rows = p_vout->p_sys->i_rows;
358     int i_cols = p_vout->p_sys->i_cols;
359
360     /* This is a new frame. Get a structure from the video_output. */
361     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
362               == NULL )
363     {
364         if( p_vout->b_die || p_vout->b_error )
365         {
366             return;
367         }
368         msleep( VOUT_OUTMEM_SLEEP );
369     }
370
371     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
372
373     for( i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
374     {
375         plane_t *p_in = p_pic->p+i_plane;
376         plane_t *p_out = p_outpic->p+i_plane;
377         int i_pitch = p_in->i_pitch;
378         int i;
379
380         for( i = 0; i < i_cols * i_rows; i++ )
381         {
382             int i_col = i % i_cols;
383             int i_row = i / i_cols;
384             int i_ocol = p_vout->p_sys->pi_order[i] % i_cols;
385             int i_orow = p_vout->p_sys->pi_order[i] / i_cols;
386             int i_last_row = i_row + 1;
387             i_orow *= p_in->i_lines / i_rows;
388             i_row *= p_in->i_lines / i_rows;
389             i_last_row *= p_in->i_lines / i_rows;
390
391             if( p_vout->p_sys->b_blackslot == VLC_TRUE
392                 && p_vout->p_sys->b_finished == VLC_FALSE
393                 && i == p_vout->p_sys->i_selected )
394             {
395                 uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
396                 for( ; i_row < i_last_row; i_row++, i_orow++ )
397                 {
398                     p_vout->p_libvlc->
399                     pf_memset( p_out->p_pixels + i_row * i_pitch
400                                                + i_col * i_pitch / i_cols,
401                                color, i_pitch / i_cols );
402                 }
403             }
404             else
405             {
406                 for( ; i_row < i_last_row; i_row++, i_orow++ )
407                 {
408                     p_vout->p_libvlc->
409                     pf_memcpy( p_out->p_pixels + i_row * i_pitch
410                                                + i_col * i_pitch / i_cols,
411                                p_in->p_pixels + i_orow * i_pitch
412                                               + i_ocol * i_pitch / i_cols,
413                                i_pitch / i_cols );
414                 }
415             }
416         }
417     }
418
419     if(    p_vout->p_sys->i_selected != -1
420         && p_vout->p_sys->b_blackslot == VLC_FALSE )
421     {
422         plane_t *p_in = p_pic->p+Y_PLANE;
423         plane_t *p_out = p_outpic->p+Y_PLANE;
424         int i_pitch = p_in->i_pitch;
425         int i_col = p_vout->p_sys->i_selected % i_cols;
426         int i_row = p_vout->p_sys->i_selected / i_cols;
427         int i_last_row = i_row + 1;
428         i_row *= p_in->i_lines / i_rows;
429         i_last_row *= p_in->i_lines / i_rows;
430         p_vout->p_libvlc->
431         pf_memset( p_out->p_pixels + i_row * i_pitch
432                                    + i_col * i_pitch / i_cols,
433                    0xff, i_pitch / i_cols );
434         for( ; i_row < i_last_row; i_row++ )
435         {
436             p_out->p_pixels[   i_row * i_pitch
437                              + i_col * i_pitch / i_cols ] = 0xff;
438             p_out->p_pixels[ i_row * i_pitch
439                              + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
440         }
441         i_row--;
442         p_vout->p_libvlc->
443         pf_memset( p_out->p_pixels + i_row * i_pitch
444                                    + i_col * i_pitch / i_cols,
445                    0xff, i_pitch / i_cols );
446     }
447
448     if( p_vout->p_sys->b_finished == VLC_TRUE )
449     {
450         int i, j;
451         plane_t *p_out = p_outpic->p+Y_PLANE;
452         int i_pitch = p_out->i_pitch;
453         for( i = 0; i < SHUFFLE_HEIGHT; i++ )
454         {
455             for( j = 0; j < SHUFFLE_WIDTH; j++ )
456             {
457                 if( shuffle_button[i][j] == '.' )
458                    p_out->p_pixels[ i * i_pitch + j ] = 0xff;
459             }
460         }
461     }
462
463     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
464 }
465
466 /*****************************************************************************
467  * SendEvents: forward mouse and keyboard events to the parent p_vout
468  *****************************************************************************/
469 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
470                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
471 {
472     var_Set( (vlc_object_t *)p_data, psz_var, newval );
473
474     return VLC_SUCCESS;
475 }
476
477 /*****************************************************************************
478  * SendEventsToChild: forward events to the child/children vout
479  *****************************************************************************/
480 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
481                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
482 {
483     vout_thread_t *p_vout = (vout_thread_t *)p_this;
484     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
485     return VLC_SUCCESS;
486 }
487
488 /*****************************************************************************
489  * MouseEvent: callback for mouse events
490  *****************************************************************************/
491 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
492                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
493 {
494     vout_thread_t *p_vout = (vout_thread_t*)p_data;
495     int i_x, i_y;
496     int i_v;
497
498 #define MOUSE_DOWN    1
499 #define MOUSE_CLICKED 2
500 #define MOUSE_MOVE_X  4
501 #define MOUSE_MOVE_Y  8
502 #define MOUSE_MOVE    12
503     uint8_t mouse= 0;
504
505     int v_h = p_vout->output.i_height;
506     int v_w = p_vout->output.i_width;
507     int i_pos;
508
509     if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
510     if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
511     if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
512
513     i_v = var_GetInteger( p_vout->p_sys->p_vout, "mouse-button-down" );
514     if( i_v & 0x1 ) mouse |= MOUSE_DOWN;
515     i_y = var_GetInteger( p_vout->p_sys->p_vout, "mouse-y" );
516     i_x = var_GetInteger( p_vout->p_sys->p_vout, "mouse-x" );
517
518     if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
519         return VLC_SUCCESS;
520
521     if( mouse & MOUSE_CLICKED )
522     {
523         i_pos = p_vout->p_sys->i_cols * ( ( p_vout->p_sys->i_rows * i_y ) / v_h ) + (p_vout->p_sys->i_cols * i_x ) / v_w;
524         if( p_vout->p_sys->b_finished == VLC_TRUE
525             && i_x < SHUFFLE_WIDTH && i_y < SHUFFLE_HEIGHT )
526         {
527             shuffle( p_vout->p_sys );
528         }
529         else if( p_vout->p_sys->i_selected == -1 )
530         {
531             p_vout->p_sys->i_selected = i_pos;
532         }
533         else if( p_vout->p_sys->i_selected == i_pos
534                  && p_vout->p_sys->b_blackslot == VLC_FALSE )
535         {
536             p_vout->p_sys->i_selected = -1;
537         }
538         else if(    ( p_vout->p_sys->i_selected == i_pos + 1
539                       && p_vout->p_sys->i_selected%p_vout->p_sys->i_cols != 0 )
540                  || ( p_vout->p_sys->i_selected == i_pos - 1
541                       && i_pos % p_vout->p_sys->i_cols != 0 )
542                  || p_vout->p_sys->i_selected == i_pos + p_vout->p_sys->i_cols
543                  || p_vout->p_sys->i_selected == i_pos - p_vout->p_sys->i_cols )
544         {
545             int a = p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ];
546             p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ] =
547                 p_vout->p_sys->pi_order[ i_pos ];
548             p_vout->p_sys->pi_order[ i_pos ] = a;
549             if( p_vout->p_sys->b_blackslot == VLC_TRUE )
550                 p_vout->p_sys->i_selected = i_pos;
551             else
552                 p_vout->p_sys->i_selected = -1;
553
554             p_vout->p_sys->b_finished = finished( p_vout->p_sys );
555         }
556     }
557     return VLC_SUCCESS;
558 }
559
560 static int PuzzleCallback( vlc_object_t *p_this, char const *psz_var,
561                            vlc_value_t oldval, vlc_value_t newval,
562                            void *p_data )
563 {
564     vout_sys_t *p_sys = (vout_sys_t *)p_data;
565     if( !strcmp( psz_var, CFG_PREFIX "rows" ) )
566     {
567         p_sys->i_rows = __MAX( 1, newval.i_int );
568     }
569     else if( !strcmp( psz_var, CFG_PREFIX "cols" ) )
570     {
571         p_sys->i_cols = __MAX( 1, newval.i_int );
572     }
573     else if( !strcmp( psz_var, CFG_PREFIX "black-slot" ) )
574     {
575         p_sys->b_blackslot = newval.b_bool;
576     }
577     shuffle( p_sys );
578     return VLC_SUCCESS;
579 }