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 DEL_PARENT_CALLBACKS( SendEventsToChild );
294 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
296 /* Free the fake output buffers we allocated */
297 for( i_index = I_OUTPUTPICTURES ; i_index ; )
300 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
303 var_DelCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout);
304 var_DelCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout);
305 var_DelCallback( p_vout->p_sys->p_vout, "mouse-clicked", MouseEvent, p_vout);
307 vout_CloseAndRelease( p_vout->p_sys->p_vout );
310 #define SHUFFLE_WIDTH 81
311 #define SHUFFLE_HEIGHT 13
312 static const char *shuffle_button[] =
314 ".................................................................................",
315 ".............. ............................ ........ ...... ...............",
316 ".............. ........................... ......... ........ ...............",
317 ".............. ........................... ......... ........ ...............",
318 ".. ....... . ....... .... ...... ...... ...... ........ ...",
319 ". .... ...... ... ...... .... ....... ......... ........ ....... .. ..",
320 ". ........... .... ...... .... ....... ......... ........ ...... .... .",
321 ". ....... .... ...... .... ....... ......... ........ ...... .",
322 ".. ...... .... ...... .... ....... ......... ........ ...... .......",
323 "...... ...... .... ...... .... ....... ......... ........ ...... .......",
324 ". .... ...... .... ...... ... ....... ......... ........ ....... .... .",
325 ".. ....... .... ....... . ....... ......... ........ ........ ..",
326 "................................................................................."};
329 /*****************************************************************************
330 * Destroy: destroy Magnify video thread output method
331 *****************************************************************************/
332 static void Destroy( vlc_object_t *p_this )
334 vout_thread_t *p_vout = (vout_thread_t *)p_this;
336 image_HandlerDelete( p_vout->p_sys->p_image );
337 free( p_vout->p_sys->pi_order );
339 free( p_vout->p_sys );
342 /*****************************************************************************
343 * Render: displays previously rendered output
344 *****************************************************************************/
345 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
349 //video_format_t fmt_out;
350 // memset( &fmt_out, 0, sizeof(video_format_t) );
351 //picture_t *p_converted;
355 int i_rows = p_vout->p_sys->i_rows;
356 int i_cols = p_vout->p_sys->i_cols;
358 /* This is a new frame. Get a structure from the video_output. */
359 while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
362 if( !vlc_object_alive (p_vout) || p_vout->b_error )
366 msleep( VOUT_OUTMEM_SLEEP );
369 vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
371 for( i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
373 plane_t *p_in = p_pic->p+i_plane;
374 plane_t *p_out = p_outpic->p+i_plane;
375 int i_pitch = p_in->i_pitch;
378 for( i = 0; i < i_cols * i_rows; i++ )
380 int i_col = i % i_cols;
381 int i_row = i / i_cols;
382 int i_ocol = p_vout->p_sys->pi_order[i] % i_cols;
383 int i_orow = p_vout->p_sys->pi_order[i] / i_cols;
384 int i_last_row = i_row + 1;
385 i_orow *= p_in->i_lines / i_rows;
386 i_row *= p_in->i_lines / i_rows;
387 i_last_row *= p_in->i_lines / i_rows;
389 if( p_vout->p_sys->b_blackslot == true
390 && p_vout->p_sys->b_finished == false
391 && i == p_vout->p_sys->i_selected )
393 uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
394 for( ; i_row < i_last_row; i_row++, i_orow++ )
396 vlc_memset( p_out->p_pixels + i_row * i_pitch
397 + i_col * i_pitch / i_cols,
398 color, i_pitch / i_cols );
403 for( ; i_row < i_last_row; i_row++, i_orow++ )
405 vlc_memcpy( p_out->p_pixels + i_row * i_pitch
406 + i_col * i_pitch / i_cols,
407 p_in->p_pixels + i_orow * i_pitch
408 + i_ocol * i_pitch / i_cols,
415 if( p_vout->p_sys->i_selected != -1
416 && p_vout->p_sys->b_blackslot == false )
418 plane_t *p_in = p_pic->p+Y_PLANE;
419 plane_t *p_out = p_outpic->p+Y_PLANE;
420 int i_pitch = p_in->i_pitch;
421 int i_col = p_vout->p_sys->i_selected % i_cols;
422 int i_row = p_vout->p_sys->i_selected / i_cols;
423 int i_last_row = i_row + 1;
424 i_row *= p_in->i_lines / i_rows;
425 i_last_row *= p_in->i_lines / i_rows;
426 vlc_memset( p_out->p_pixels + i_row * i_pitch
427 + i_col * i_pitch / i_cols,
428 0xff, i_pitch / i_cols );
429 for( ; i_row < i_last_row; i_row++ )
431 p_out->p_pixels[ i_row * i_pitch
432 + i_col * i_pitch / i_cols ] = 0xff;
433 p_out->p_pixels[ i_row * i_pitch
434 + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
437 vlc_memset( p_out->p_pixels + i_row * i_pitch
438 + i_col * i_pitch / i_cols,
439 0xff, i_pitch / i_cols );
442 if( p_vout->p_sys->b_finished == true )
445 plane_t *p_out = p_outpic->p+Y_PLANE;
446 int i_pitch = p_out->i_pitch;
447 for( i = 0; i < SHUFFLE_HEIGHT; i++ )
449 for( j = 0; j < SHUFFLE_WIDTH; j++ )
451 if( shuffle_button[i][j] == '.' )
452 p_out->p_pixels[ i * i_pitch + j ] = 0xff;
457 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
460 /*****************************************************************************
461 * SendEvents: forward mouse and keyboard events to the parent p_vout
462 *****************************************************************************/
463 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
464 vlc_value_t oldval, vlc_value_t newval, void *p_data )
466 VLC_UNUSED(p_this); VLC_UNUSED(oldval);
468 var_Set( (vlc_object_t *)p_data, psz_var, newval );
473 /*****************************************************************************
474 * SendEventsToChild: forward events to the child/children vout
475 *****************************************************************************/
476 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
477 vlc_value_t oldval, vlc_value_t newval, void *p_data )
479 VLC_UNUSED(p_data); VLC_UNUSED(oldval);
480 vout_thread_t *p_vout = (vout_thread_t *)p_this;
481 var_Set( p_vout->p_sys->p_vout, psz_var, newval );
485 /*****************************************************************************
486 * MouseEvent: callback for mouse events
487 *****************************************************************************/
488 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
489 vlc_value_t oldval, vlc_value_t newval, void *p_data )
491 VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(newval);
492 vout_thread_t *p_vout = (vout_thread_t*)p_data;
497 #define MOUSE_CLICKED 2
498 #define MOUSE_MOVE_X 4
499 #define MOUSE_MOVE_Y 8
500 #define MOUSE_MOVE 12
503 int v_h = p_vout->output.i_height;
504 int v_w = p_vout->output.i_width;
507 if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
508 if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
509 if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
511 i_v = var_GetInteger( p_vout->p_sys->p_vout, "mouse-button-down" );
512 if( i_v & 0x1 ) mouse |= MOUSE_DOWN;
513 i_y = var_GetInteger( p_vout->p_sys->p_vout, "mouse-y" );
514 i_x = var_GetInteger( p_vout->p_sys->p_vout, "mouse-x" );
516 if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
519 if( mouse & MOUSE_CLICKED )
521 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;
522 if( p_vout->p_sys->b_finished == true
523 && i_x < SHUFFLE_WIDTH && i_y < SHUFFLE_HEIGHT )
525 shuffle( p_vout->p_sys );
527 else if( p_vout->p_sys->i_selected == -1 )
529 p_vout->p_sys->i_selected = i_pos;
531 else if( p_vout->p_sys->i_selected == i_pos
532 && p_vout->p_sys->b_blackslot == false )
534 p_vout->p_sys->i_selected = -1;
536 else if( ( p_vout->p_sys->i_selected == i_pos + 1
537 && p_vout->p_sys->i_selected%p_vout->p_sys->i_cols != 0 )
538 || ( p_vout->p_sys->i_selected == i_pos - 1
539 && i_pos % p_vout->p_sys->i_cols != 0 )
540 || p_vout->p_sys->i_selected == i_pos + p_vout->p_sys->i_cols
541 || p_vout->p_sys->i_selected == i_pos - p_vout->p_sys->i_cols )
543 int a = p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ];
544 p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ] =
545 p_vout->p_sys->pi_order[ i_pos ];
546 p_vout->p_sys->pi_order[ i_pos ] = a;
547 if( p_vout->p_sys->b_blackslot == true )
548 p_vout->p_sys->i_selected = i_pos;
550 p_vout->p_sys->i_selected = -1;
552 p_vout->p_sys->b_finished = finished( p_vout->p_sys );
558 static int PuzzleCallback( vlc_object_t *p_this, char const *psz_var,
559 vlc_value_t oldval, vlc_value_t newval,
562 VLC_UNUSED(p_this); VLC_UNUSED(oldval);
563 vout_sys_t *p_sys = (vout_sys_t *)p_data;
564 if( !strcmp( psz_var, CFG_PREFIX "rows" ) )
566 p_sys->i_rows = __MAX( 1, newval.i_int );
568 else if( !strcmp( psz_var, CFG_PREFIX "cols" ) )
570 p_sys->i_cols = __MAX( 1, newval.i_int );
572 else if( !strcmp( psz_var, CFG_PREFIX "black-slot" ) )
574 p_sys->b_blackslot = newval.b_bool;