]> git.sesse.net Git - vlc/blob - modules/video_filter/puzzle.c
Put video in black slot when puzzle is solved
[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 /*****************************************************************************
56  * Module descriptor
57  *****************************************************************************/
58
59 #define ROWS_TEXT N_("Number of puzzle rows")
60 #define ROWS_LONGTEXT N_("Number of puzzle rows")
61 #define COLS_TEXT N_("Number of puzzle columns")
62 #define COLS_LONGTEXT N_("Number of puzzle columns")
63 #define BLACKSLOT_TEXT N_("Make one tile a black slot")
64 #define BLACKSLOT_LONGTEXT N_("Make one slot black. Other tiles can only be swapped with the black slot.")
65
66 vlc_module_begin();
67     set_description( _("Puzzle interactive game video filter") );
68     set_shortname( _( "Puzzle" ));
69     set_capability( "video filter", 0 );
70     set_category( CAT_VIDEO );
71     set_subcategory( SUBCAT_VIDEO_VFILTER );
72
73     add_integer_with_range( "puzzle-rows", 4, 1, 128, NULL,
74                             ROWS_TEXT, ROWS_LONGTEXT, VLC_FALSE );
75     add_integer_with_range( "puzzle-cols", 4, 1, 128, NULL,
76                             COLS_TEXT, COLS_LONGTEXT, VLC_FALSE );
77     add_bool( "puzzle-black-slot", 0, NULL,
78               BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, VLC_FALSE );
79
80     set_callbacks( Create, Destroy );
81 vlc_module_end();
82
83 /*****************************************************************************
84  * vout_sys_t: Magnify video output method descriptor
85  *****************************************************************************/
86 struct vout_sys_t
87 {
88     vout_thread_t *p_vout;
89
90     image_handler_t *p_image;
91
92     int i_cols;
93     int i_rows;
94     int *pi_order;
95     int i_selected;
96     vlc_bool_t b_finished;
97
98     vlc_bool_t b_blackslot;
99 };
100
101 /*****************************************************************************
102  * Control: control facility for the vout (forwards to child vout)
103  *****************************************************************************/
104 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
105 {
106     return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
107 }
108
109 /*****************************************************************************
110  * Misc stuff...
111  *****************************************************************************/
112 static vlc_bool_t finished( vout_sys_t *p_sys )
113 {
114     int i;
115     for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
116     {
117         if( i != p_sys->pi_order[i] ) return VLC_FALSE;
118     }
119     return VLC_TRUE;
120 }
121 static vlc_bool_t is_valid( vout_sys_t *p_sys )
122 {
123     int i, s=0;
124     if( p_sys->b_blackslot == VLC_FALSE ) return VLC_TRUE;
125     for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
126     {
127         if( (p_sys->i_cols*p_sys->i_rows+i-p_sys->pi_order[i])%2 ) s++;
128         else s--;
129     }
130     if( s!=0 ) return VLC_FALSE;
131     else return VLC_TRUE;
132 }
133 static void shuffle( vout_sys_t *p_sys )
134 {
135     int i, c;
136     free( p_sys->pi_order );
137     p_sys->pi_order = malloc( p_sys->i_cols * p_sys->i_rows * sizeof( int ) );
138     do
139     {
140         for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
141         {
142             p_sys->pi_order[i] = -1;
143         }
144         i = 0;
145         for( c = 0; c < p_sys->i_cols * p_sys->i_rows; )
146         {
147             i = rand()%( p_sys->i_cols * p_sys->i_rows );
148             if( p_sys->pi_order[i] == -1 )
149             {
150                 p_sys->pi_order[i] = c;
151                 c++;
152             }
153         }
154         p_sys->b_finished = finished( p_sys );
155     } while(    p_sys->b_finished == VLC_TRUE
156              && is_valid( p_sys ) == VLC_FALSE );
157
158     if( p_sys->b_blackslot == VLC_TRUE )
159     {
160         for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
161         {
162             if( p_sys->pi_order[i] ==
163                 ( p_sys->i_cols - 1 ) * p_sys->i_rows )
164             {
165                 p_sys->i_selected = i;
166                 break;
167             }
168         }
169     }
170     else
171     {
172         p_sys->i_selected = -1;
173     }
174     printf( "selected: %d\n", p_sys->i_selected );
175 }
176
177 /*****************************************************************************
178  * Create: allocates Magnify video thread output method
179  *****************************************************************************/
180 static int Create( vlc_object_t *p_this )
181 {
182     vout_thread_t *p_vout = (vout_thread_t *)p_this;
183
184     /* Allocate structure */
185     p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
186     if( p_vout->p_sys == NULL )
187     {
188         msg_Err( p_vout, "out of memory" );
189         return VLC_ENOMEM;
190     }
191
192     p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
193
194     p_vout->p_sys->i_rows = config_GetInt( p_vout, "puzzle-rows" );
195     p_vout->p_sys->i_cols = config_GetInt( p_vout, "puzzle-cols" );
196     p_vout->p_sys->b_blackslot = config_GetInt( p_vout, "puzzle-black-slot" );
197
198     p_vout->p_sys->pi_order = NULL;
199     shuffle( p_vout->p_sys );
200
201     p_vout->pf_init = Init;
202     p_vout->pf_end = End;
203     p_vout->pf_manage = NULL;
204     p_vout->pf_render = Render;
205     p_vout->pf_display = NULL;
206     p_vout->pf_control = Control;
207
208     return VLC_SUCCESS;
209 }
210
211 /*****************************************************************************
212  * Init: initialize Magnify video thread output method
213  *****************************************************************************/
214 static int Init( vout_thread_t *p_vout )
215 {
216     int i_index;
217     picture_t *p_pic;
218     video_format_t fmt = {0};
219
220     I_OUTPUTPICTURES = 0;
221
222     /* Initialize the output structure */
223     p_vout->output.i_chroma = p_vout->render.i_chroma;
224     p_vout->output.i_width  = p_vout->render.i_width;
225     p_vout->output.i_height = p_vout->render.i_height;
226     p_vout->output.i_aspect = p_vout->render.i_aspect;
227
228     p_vout->fmt_out = p_vout->fmt_in;
229     fmt = p_vout->fmt_out;
230
231     /* Try to open the real video output */
232     msg_Dbg( p_vout, "spawning the real video output" );
233
234     p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
235
236     /* Everything failed */
237     if( p_vout->p_sys->p_vout == NULL )
238     {
239         msg_Err( p_vout, "cannot open vout, aborting" );
240         return VLC_EGENERIC;
241     }
242
243     var_AddCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout );
244     var_AddCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout );
245     var_AddCallback( p_vout->p_sys->p_vout, "mouse-clicked",
246                      MouseEvent, p_vout);
247
248     ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
249     ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
250     ADD_PARENT_CALLBACKS( SendEventsToChild );
251
252     return VLC_SUCCESS;
253 }
254
255 /*****************************************************************************
256  * End: terminate Magnify video thread output method
257  *****************************************************************************/
258 static void End( vout_thread_t *p_vout )
259 {
260     int i_index;
261
262     /* Free the fake output buffers we allocated */
263     for( i_index = I_OUTPUTPICTURES ; i_index ; )
264     {
265         i_index--;
266         free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
267     }
268
269     var_DelCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout);
270     var_DelCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout);
271     var_DelCallback( p_vout->p_sys->p_vout, "mouse-clicked", MouseEvent, p_vout);
272 }
273
274 /*****************************************************************************
275  * Destroy: destroy Magnify video thread output method
276  *****************************************************************************/
277 static void Destroy( vlc_object_t *p_this )
278 {
279     vout_thread_t *p_vout = (vout_thread_t *)p_this;
280
281     if( p_vout->p_sys->p_vout )
282     {
283         DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
284         vlc_object_detach( p_vout->p_sys->p_vout );
285         vout_Destroy( p_vout->p_sys->p_vout );
286     }
287
288     image_HandlerDelete( p_vout->p_sys->p_image );
289     free( p_vout->p_sys->pi_order );
290
291     DEL_PARENT_CALLBACKS( SendEventsToChild );
292
293     free( p_vout->p_sys );
294 }
295
296 /*****************************************************************************
297  * Render: displays previously rendered output
298  *****************************************************************************/
299 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
300 {
301     picture_t *p_outpic;
302
303     //video_format_t fmt_out = {0};
304     //picture_t *p_converted;
305
306     int i_plane;
307
308     int i_rows = p_vout->p_sys->i_rows;
309     int i_cols = p_vout->p_sys->i_cols;
310
311     /* This is a new frame. Get a structure from the video_output. */
312     while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
313               == NULL )
314     {
315         if( p_vout->b_die || p_vout->b_error )
316         {
317             return;
318         }
319         msleep( VOUT_OUTMEM_SLEEP );
320     }
321
322     vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
323
324     for( i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
325     {
326         plane_t *p_in = p_pic->p+i_plane;
327         plane_t *p_out = p_outpic->p+i_plane;
328         int i_pitch = p_in->i_pitch;
329         int i;
330
331         for( i = 0; i < i_cols * i_rows; i++ )
332         {
333             int i_col = i % i_cols;
334             int i_row = i / i_cols;
335             int i_ocol = p_vout->p_sys->pi_order[i] % i_cols;
336             int i_orow = p_vout->p_sys->pi_order[i] / i_cols;
337             int i_last_row = i_row + 1;
338             i_orow *= p_in->i_lines / i_rows;
339             i_row *= p_in->i_lines / i_rows;
340             i_last_row *= p_in->i_lines / i_rows;
341
342             if( p_vout->p_sys->b_blackslot == VLC_TRUE
343                 && p_vout->p_sys->b_finished == VLC_FALSE
344                 && i == p_vout->p_sys->i_selected )
345             {
346                 uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
347                 for( ; i_row < i_last_row; i_row++, i_orow++ )
348                 {
349                     memset( p_out->p_pixels + i_row * i_pitch
350                                             + i_col * i_pitch / i_cols,
351                             color, i_pitch / i_cols );
352                 }
353             }
354             else
355             {
356                 for( ; i_row < i_last_row; i_row++, i_orow++ )
357                 {
358                     memcpy( p_out->p_pixels + i_row * i_pitch
359                                             + i_col * i_pitch / i_cols,
360                             p_in->p_pixels + i_orow * i_pitch
361                                            + i_ocol * i_pitch / i_cols,
362                             i_pitch / i_cols );
363                 }
364             }
365         }
366     }
367
368     if(    p_vout->p_sys->i_selected != -1
369         && p_vout->p_sys->b_blackslot == VLC_FALSE )
370     {
371         plane_t *p_in = p_pic->p+Y_PLANE;
372         plane_t *p_out = p_outpic->p+Y_PLANE;
373         int i_pitch = p_in->i_pitch;
374         int i_col = p_vout->p_sys->i_selected % i_cols;
375         int i_row = p_vout->p_sys->i_selected / i_cols;
376         int i_last_row = i_row + 1;
377         i_row *= p_in->i_lines / i_rows;
378         i_last_row *= p_in->i_lines / i_rows;
379         memset( p_out->p_pixels + i_row * i_pitch
380                                 + i_col * i_pitch / i_cols,
381                 0xff, i_pitch / i_cols );
382         for( ; i_row < i_last_row; i_row++ )
383         {
384             p_out->p_pixels[   i_row * i_pitch
385                              + i_col * i_pitch / i_cols ] = 0xff;
386             p_out->p_pixels[ i_row * i_pitch
387                              + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
388         }
389         i_row--;
390         memset( p_out->p_pixels + i_row * i_pitch
391                                 + i_col * i_pitch / i_cols,
392                 0xff, i_pitch / i_cols );
393     }
394
395     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
396 }
397
398 /*****************************************************************************
399  * SendEvents: forward mouse and keyboard events to the parent p_vout
400  *****************************************************************************/
401 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
402                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
403 {
404     var_Set( (vlc_object_t *)p_data, psz_var, newval );
405
406     return VLC_SUCCESS;
407 }
408
409 /*****************************************************************************
410  * SendEventsToChild: forward events to the child/children vout
411  *****************************************************************************/
412 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
413                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
414 {
415     vout_thread_t *p_vout = (vout_thread_t *)p_this;
416     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
417     return VLC_SUCCESS;
418 }
419
420 /*****************************************************************************
421  * MouseEvent: callback for mouse events
422  *****************************************************************************/
423 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
424                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
425 {
426     vout_thread_t *p_vout = (vout_thread_t*)p_data;
427     int i_x, i_y;
428     int i_v;
429
430 #define MOUSE_DOWN    1
431 #define MOUSE_CLICKED 2
432 #define MOUSE_MOVE_X  4
433 #define MOUSE_MOVE_Y  8
434 #define MOUSE_MOVE    12
435     uint8_t mouse= 0;
436
437     int v_h = p_vout->output.i_height;
438     int v_w = p_vout->output.i_width;
439     int i_pos;
440
441     if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
442     if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
443     if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
444
445     i_v = var_GetInteger( p_vout->p_sys->p_vout, "mouse-button-down" );
446     if( i_v & 0x1 ) mouse |= MOUSE_DOWN;
447     i_y = var_GetInteger( p_vout->p_sys->p_vout, "mouse-y" );
448     i_x = var_GetInteger( p_vout->p_sys->p_vout, "mouse-x" );
449
450     if( mouse & MOUSE_CLICKED )
451     {
452         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;
453         if( p_vout->p_sys->b_finished == VLC_TRUE )
454         {
455             shuffle( p_vout->p_sys );
456         }
457         else if( p_vout->p_sys->i_selected == -1 )
458         {
459             p_vout->p_sys->i_selected = i_pos;
460         }
461         else if( p_vout->p_sys->i_selected == i_pos
462                  && p_vout->p_sys->b_blackslot == VLC_FALSE )
463         {
464             p_vout->p_sys->i_selected = -1;
465         }
466         else if(    p_vout->p_sys->i_selected == i_pos + 1
467                  || p_vout->p_sys->i_selected == i_pos - 1
468                  || p_vout->p_sys->i_selected == i_pos + p_vout->p_sys->i_cols
469                  || p_vout->p_sys->i_selected == i_pos - p_vout->p_sys->i_cols )
470         {
471             int a = p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ];
472             p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ] =
473                 p_vout->p_sys->pi_order[ i_pos ];
474             p_vout->p_sys->pi_order[ i_pos ] = a;
475             if( p_vout->p_sys->b_blackslot == VLC_TRUE )
476                 p_vout->p_sys->i_selected = i_pos;
477             else
478                 p_vout->p_sys->i_selected = -1;
479
480             p_vout->p_sys->b_finished = finished( p_vout->p_sys );
481         }
482     }
483     return VLC_SUCCESS;
484 }