1 /*****************************************************************************
2 * puzzle.c : Puzzle game
3 *****************************************************************************
4 * Copyright (C) 2005-2006 the VideoLAN team
7 * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
38 #include "filter_common.h"
39 #include "vlc_image.h"
40 #include "vlc_input.h"
41 #include "vlc_playlist.h"
43 /*****************************************************************************
45 *****************************************************************************/
46 static int Create ( vlc_object_t * );
47 static void Destroy ( vlc_object_t * );
49 static int Init ( vout_thread_t * );
50 static void End ( vout_thread_t * );
51 static void Render ( vout_thread_t *, picture_t * );
53 static int SendEvents ( vlc_object_t *, char const *,
54 vlc_value_t, vlc_value_t, void * );
55 static int MouseEvent ( vlc_object_t *, char const *,
56 vlc_value_t, vlc_value_t, void * );
58 static int PuzzleCallback( vlc_object_t *, char const *,
59 vlc_value_t, vlc_value_t, void * );
61 /*****************************************************************************
63 *****************************************************************************/
65 #define ROWS_TEXT N_("Number of puzzle rows")
66 #define ROWS_LONGTEXT N_("Number of puzzle rows")
67 #define COLS_TEXT N_("Number of puzzle columns")
68 #define COLS_LONGTEXT N_("Number of puzzle columns")
69 #define BLACKSLOT_TEXT N_("Make one tile a black slot")
70 #define BLACKSLOT_LONGTEXT N_("Make one slot black. Other tiles can only be swapped with the black slot.")
72 #define CFG_PREFIX "puzzle-"
75 set_description( N_("Puzzle interactive game video filter") );
76 set_shortname( N_( "Puzzle" ));
77 set_capability( "video filter", 0 );
78 set_category( CAT_VIDEO );
79 set_subcategory( SUBCAT_VIDEO_VFILTER );
81 add_integer_with_range( CFG_PREFIX "rows", 4, 1, 128, NULL,
82 ROWS_TEXT, ROWS_LONGTEXT, false );
83 add_integer_with_range( CFG_PREFIX "cols", 4, 1, 128, NULL,
84 COLS_TEXT, COLS_LONGTEXT, false );
85 add_bool( CFG_PREFIX "black-slot", 0, NULL,
86 BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, false );
88 set_callbacks( Create, Destroy );
91 static const char *const ppsz_filter_options[] = {
92 "rows", "cols", "black-slot", NULL
95 /*****************************************************************************
96 * vout_sys_t: Magnify video output method descriptor
97 *****************************************************************************/
100 vout_thread_t *p_vout;
102 image_handler_t *p_image;
113 /*****************************************************************************
114 * Control: control facility for the vout (forwards to child vout)
115 *****************************************************************************/
116 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
118 return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
121 /*****************************************************************************
123 *****************************************************************************/
124 static bool finished( vout_sys_t *p_sys )
127 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
129 if( i != p_sys->pi_order[i] ) return false;
133 static bool is_valid( vout_sys_t *p_sys )
136 if( p_sys->b_blackslot == false ) return true;
137 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
139 if( p_sys->pi_order[i] == p_sys->i_cols * p_sys->i_rows - 1 )
141 d += i / p_sys->i_cols + 1;
144 for( j = i+1; j < p_sys->i_cols * p_sys->i_rows; j++ )
146 if( p_sys->pi_order[j] == p_sys->i_cols * p_sys->i_rows - 1 )
148 if( p_sys->pi_order[i] > p_sys->pi_order[j] ) d++;
151 if( d%2!=0 ) return false;
154 static void shuffle( vout_sys_t *p_sys )
157 free( p_sys->pi_order );
158 p_sys->pi_order = malloc( p_sys->i_cols * p_sys->i_rows * sizeof( int ) );
161 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
163 p_sys->pi_order[i] = -1;
166 for( c = 0; c < p_sys->i_cols * p_sys->i_rows; )
168 i = rand()%( p_sys->i_cols * p_sys->i_rows );
169 if( p_sys->pi_order[i] == -1 )
171 p_sys->pi_order[i] = c;
175 p_sys->b_finished = finished( p_sys );
176 } while( p_sys->b_finished == true
177 || is_valid( p_sys ) == false );
179 if( p_sys->b_blackslot == true )
181 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
183 if( p_sys->pi_order[i] ==
184 p_sys->i_cols * p_sys->i_rows - 1 )
186 p_sys->i_selected = i;
193 p_sys->i_selected = -1;
197 /*****************************************************************************
198 * Create: allocates Magnify video thread output method
199 *****************************************************************************/
200 static int Create( vlc_object_t *p_this )
202 vout_thread_t *p_vout = (vout_thread_t *)p_this;
204 /* Allocate structure */
205 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
206 if( p_vout->p_sys == NULL )
209 p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
211 config_ChainParse( p_vout, CFG_PREFIX, ppsz_filter_options,
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 );
227 p_vout->p_sys->pi_order = NULL;
228 shuffle( p_vout->p_sys );
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;
240 /*****************************************************************************
241 * Init: initialize Magnify video thread output method
242 *****************************************************************************/
243 static int Init( vout_thread_t *p_vout )
248 memset( &fmt, 0, sizeof( video_format_t ) );
250 I_OUTPUTPICTURES = 0;
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;
258 p_vout->fmt_out = p_vout->fmt_in;
259 fmt = p_vout->fmt_out;
261 /* Try to open the real video output */
262 msg_Dbg( p_vout, "spawning the real video output" );
264 p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
266 /* Everything failed */
267 if( p_vout->p_sys->p_vout == NULL )
269 msg_Err( p_vout, "cannot open vout, aborting" );
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",
278 ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
279 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
280 ADD_PARENT_CALLBACKS( SendEventsToChild );
285 /*****************************************************************************
286 * End: terminate Magnify video thread output method
287 *****************************************************************************/
288 static void End( vout_thread_t *p_vout )
292 /* Free the fake output buffers we allocated */
293 for( i_index = I_OUTPUTPICTURES ; i_index ; )
296 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
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);
304 #define SHUFFLE_WIDTH 81
305 #define SHUFFLE_HEIGHT 13
306 static const char *shuffle_button[] =
308 ".................................................................................",
309 ".............. ............................ ........ ...... ...............",
310 ".............. ........................... ......... ........ ...............",
311 ".............. ........................... ......... ........ ...............",
312 ".. ....... . ....... .... ...... ...... ...... ........ ...",
313 ". .... ...... ... ...... .... ....... ......... ........ ....... .. ..",
314 ". ........... .... ...... .... ....... ......... ........ ...... .... .",
315 ". ....... .... ...... .... ....... ......... ........ ...... .",
316 ".. ...... .... ...... .... ....... ......... ........ ...... .......",
317 "...... ...... .... ...... .... ....... ......... ........ ...... .......",
318 ". .... ...... .... ...... ... ....... ......... ........ ....... .... .",
319 ".. ....... .... ....... . ....... ......... ........ ........ ..",
320 "................................................................................."};
323 /*****************************************************************************
324 * Destroy: destroy Magnify video thread output method
325 *****************************************************************************/
326 static void Destroy( vlc_object_t *p_this )
328 vout_thread_t *p_vout = (vout_thread_t *)p_this;
330 if( p_vout->p_sys->p_vout )
332 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
333 vlc_object_detach( p_vout->p_sys->p_vout );
334 vlc_object_release( p_vout->p_sys->p_vout );
337 image_HandlerDelete( p_vout->p_sys->p_image );
338 free( p_vout->p_sys->pi_order );
340 DEL_PARENT_CALLBACKS( SendEventsToChild );
342 free( p_vout->p_sys );
345 /*****************************************************************************
346 * Render: displays previously rendered output
347 *****************************************************************************/
348 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
352 //video_format_t fmt_out;
353 // memset( &fmt_out, 0, sizeof(video_format_t) );
354 //picture_t *p_converted;
358 int i_rows = p_vout->p_sys->i_rows;
359 int i_cols = p_vout->p_sys->i_cols;
361 /* This is a new frame. Get a structure from the video_output. */
362 while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
365 if( p_vout->b_die || p_vout->b_error )
369 msleep( VOUT_OUTMEM_SLEEP );
372 vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
374 for( i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
376 plane_t *p_in = p_pic->p+i_plane;
377 plane_t *p_out = p_outpic->p+i_plane;
378 int i_pitch = p_in->i_pitch;
381 for( i = 0; i < i_cols * i_rows; i++ )
383 int i_col = i % i_cols;
384 int i_row = i / i_cols;
385 int i_ocol = p_vout->p_sys->pi_order[i] % i_cols;
386 int i_orow = p_vout->p_sys->pi_order[i] / i_cols;
387 int i_last_row = i_row + 1;
388 i_orow *= p_in->i_lines / i_rows;
389 i_row *= p_in->i_lines / i_rows;
390 i_last_row *= p_in->i_lines / i_rows;
392 if( p_vout->p_sys->b_blackslot == true
393 && p_vout->p_sys->b_finished == false
394 && i == p_vout->p_sys->i_selected )
396 uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
397 for( ; i_row < i_last_row; i_row++, i_orow++ )
399 vlc_memset( p_out->p_pixels + i_row * i_pitch
400 + i_col * i_pitch / i_cols,
401 color, i_pitch / i_cols );
406 for( ; i_row < i_last_row; i_row++, i_orow++ )
408 vlc_memcpy( p_out->p_pixels + i_row * i_pitch
409 + i_col * i_pitch / i_cols,
410 p_in->p_pixels + i_orow * i_pitch
411 + i_ocol * i_pitch / i_cols,
418 if( p_vout->p_sys->i_selected != -1
419 && p_vout->p_sys->b_blackslot == false )
421 plane_t *p_in = p_pic->p+Y_PLANE;
422 plane_t *p_out = p_outpic->p+Y_PLANE;
423 int i_pitch = p_in->i_pitch;
424 int i_col = p_vout->p_sys->i_selected % i_cols;
425 int i_row = p_vout->p_sys->i_selected / i_cols;
426 int i_last_row = i_row + 1;
427 i_row *= p_in->i_lines / i_rows;
428 i_last_row *= p_in->i_lines / i_rows;
429 vlc_memset( p_out->p_pixels + i_row * i_pitch
430 + i_col * i_pitch / i_cols,
431 0xff, i_pitch / i_cols );
432 for( ; i_row < i_last_row; i_row++ )
434 p_out->p_pixels[ i_row * i_pitch
435 + i_col * i_pitch / i_cols ] = 0xff;
436 p_out->p_pixels[ i_row * i_pitch
437 + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
440 vlc_memset( p_out->p_pixels + i_row * i_pitch
441 + i_col * i_pitch / i_cols,
442 0xff, i_pitch / i_cols );
445 if( p_vout->p_sys->b_finished == true )
448 plane_t *p_out = p_outpic->p+Y_PLANE;
449 int i_pitch = p_out->i_pitch;
450 for( i = 0; i < SHUFFLE_HEIGHT; i++ )
452 for( j = 0; j < SHUFFLE_WIDTH; j++ )
454 if( shuffle_button[i][j] == '.' )
455 p_out->p_pixels[ i * i_pitch + j ] = 0xff;
460 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
463 /*****************************************************************************
464 * SendEvents: forward mouse and keyboard events to the parent p_vout
465 *****************************************************************************/
466 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
467 vlc_value_t oldval, vlc_value_t newval, void *p_data )
469 VLC_UNUSED(p_this); VLC_UNUSED(oldval);
471 var_Set( (vlc_object_t *)p_data, psz_var, newval );
476 /*****************************************************************************
477 * SendEventsToChild: forward events to the child/children vout
478 *****************************************************************************/
479 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
480 vlc_value_t oldval, vlc_value_t newval, void *p_data )
482 VLC_UNUSED(p_data); VLC_UNUSED(oldval);
483 vout_thread_t *p_vout = (vout_thread_t *)p_this;
484 var_Set( p_vout->p_sys->p_vout, psz_var, newval );
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 )
494 VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(newval);
495 vout_thread_t *p_vout = (vout_thread_t*)p_data;
500 #define MOUSE_CLICKED 2
501 #define MOUSE_MOVE_X 4
502 #define MOUSE_MOVE_Y 8
503 #define MOUSE_MOVE 12
506 int v_h = p_vout->output.i_height;
507 int v_w = p_vout->output.i_width;
510 if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
511 if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
512 if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
514 i_v = var_GetInteger( p_vout->p_sys->p_vout, "mouse-button-down" );
515 if( i_v & 0x1 ) mouse |= MOUSE_DOWN;
516 i_y = var_GetInteger( p_vout->p_sys->p_vout, "mouse-y" );
517 i_x = var_GetInteger( p_vout->p_sys->p_vout, "mouse-x" );
519 if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
522 if( mouse & MOUSE_CLICKED )
524 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;
525 if( p_vout->p_sys->b_finished == true
526 && i_x < SHUFFLE_WIDTH && i_y < SHUFFLE_HEIGHT )
528 shuffle( p_vout->p_sys );
530 else if( p_vout->p_sys->i_selected == -1 )
532 p_vout->p_sys->i_selected = i_pos;
534 else if( p_vout->p_sys->i_selected == i_pos
535 && p_vout->p_sys->b_blackslot == false )
537 p_vout->p_sys->i_selected = -1;
539 else if( ( p_vout->p_sys->i_selected == i_pos + 1
540 && p_vout->p_sys->i_selected%p_vout->p_sys->i_cols != 0 )
541 || ( p_vout->p_sys->i_selected == i_pos - 1
542 && i_pos % p_vout->p_sys->i_cols != 0 )
543 || p_vout->p_sys->i_selected == i_pos + p_vout->p_sys->i_cols
544 || p_vout->p_sys->i_selected == i_pos - p_vout->p_sys->i_cols )
546 int a = p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ];
547 p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ] =
548 p_vout->p_sys->pi_order[ i_pos ];
549 p_vout->p_sys->pi_order[ i_pos ] = a;
550 if( p_vout->p_sys->b_blackslot == true )
551 p_vout->p_sys->i_selected = i_pos;
553 p_vout->p_sys->i_selected = -1;
555 p_vout->p_sys->b_finished = finished( p_vout->p_sys );
561 static int PuzzleCallback( vlc_object_t *p_this, char const *psz_var,
562 vlc_value_t oldval, vlc_value_t newval,
565 VLC_UNUSED(p_this); VLC_UNUSED(oldval);
566 vout_sys_t *p_sys = (vout_sys_t *)p_data;
567 if( !strcmp( psz_var, CFG_PREFIX "rows" ) )
569 p_sys->i_rows = __MAX( 1, newval.i_int );
571 else if( !strcmp( psz_var, CFG_PREFIX "cols" ) )
573 p_sys->i_cols = __MAX( 1, newval.i_int );
575 else if( !strcmp( psz_var, CFG_PREFIX "black-slot" ) )
577 p_sys->b_blackslot = newval.b_bool;