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 MouseEvent ( vlc_object_t *, char const *,
54 vlc_value_t, vlc_value_t, void * );
56 static int PuzzleCallback( vlc_object_t *, char const *,
57 vlc_value_t, vlc_value_t, void * );
59 /*****************************************************************************
61 *****************************************************************************/
63 #define ROWS_TEXT N_("Number of puzzle rows")
64 #define ROWS_LONGTEXT N_("Number of puzzle rows")
65 #define COLS_TEXT N_("Number of puzzle columns")
66 #define COLS_LONGTEXT N_("Number of puzzle columns")
67 #define BLACKSLOT_TEXT N_("Make one tile a black slot")
68 #define BLACKSLOT_LONGTEXT N_("Make one slot black. Other tiles can only be swapped with the black slot.")
70 #define CFG_PREFIX "puzzle-"
73 set_description( N_("Puzzle interactive game video filter") )
74 set_shortname( N_( "Puzzle" ))
75 set_capability( "video filter", 0 )
76 set_category( CAT_VIDEO )
77 set_subcategory( SUBCAT_VIDEO_VFILTER )
79 add_integer_with_range( CFG_PREFIX "rows", 4, 1, 128, NULL,
80 ROWS_TEXT, ROWS_LONGTEXT, false )
81 add_integer_with_range( CFG_PREFIX "cols", 4, 1, 128, NULL,
82 COLS_TEXT, COLS_LONGTEXT, false )
83 add_bool( CFG_PREFIX "black-slot", 0, NULL,
84 BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, false )
86 set_callbacks( Create, Destroy )
89 static const char *const ppsz_filter_options[] = {
90 "rows", "cols", "black-slot", NULL
93 /*****************************************************************************
94 * vout_sys_t: Magnify video output method descriptor
95 *****************************************************************************/
98 vout_thread_t *p_vout;
100 image_handler_t *p_image;
111 /*****************************************************************************
112 * Control: control facility for the vout (forwards to child vout)
113 *****************************************************************************/
114 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
116 return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
119 /*****************************************************************************
121 *****************************************************************************/
122 static bool finished( vout_sys_t *p_sys )
125 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
127 if( i != p_sys->pi_order[i] ) return false;
131 static bool is_valid( vout_sys_t *p_sys )
134 if( p_sys->b_blackslot == false ) return true;
135 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
137 if( p_sys->pi_order[i] == p_sys->i_cols * p_sys->i_rows - 1 )
139 d += i / p_sys->i_cols + 1;
142 for( j = i+1; j < p_sys->i_cols * p_sys->i_rows; j++ )
144 if( p_sys->pi_order[j] == p_sys->i_cols * p_sys->i_rows - 1 )
146 if( p_sys->pi_order[i] > p_sys->pi_order[j] ) d++;
149 if( d%2!=0 ) return false;
152 static void shuffle( vout_sys_t *p_sys )
155 free( p_sys->pi_order );
156 p_sys->pi_order = malloc( p_sys->i_cols * p_sys->i_rows * sizeof( int ) );
159 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
161 p_sys->pi_order[i] = -1;
164 for( c = 0; c < p_sys->i_cols * p_sys->i_rows; )
166 i = rand()%( p_sys->i_cols * p_sys->i_rows );
167 if( p_sys->pi_order[i] == -1 )
169 p_sys->pi_order[i] = c;
173 p_sys->b_finished = finished( p_sys );
174 } while( p_sys->b_finished == true
175 || is_valid( p_sys ) == false );
177 if( p_sys->b_blackslot == true )
179 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
181 if( p_sys->pi_order[i] ==
182 p_sys->i_cols * p_sys->i_rows - 1 )
184 p_sys->i_selected = i;
191 p_sys->i_selected = -1;
195 /*****************************************************************************
196 * Create: allocates Magnify video thread output method
197 *****************************************************************************/
198 static int Create( vlc_object_t *p_this )
200 vout_thread_t *p_vout = (vout_thread_t *)p_this;
202 /* Allocate structure */
203 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
204 if( p_vout->p_sys == NULL )
207 p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
209 config_ChainParse( p_vout, CFG_PREFIX, ppsz_filter_options,
212 p_vout->p_sys->i_rows =
213 var_CreateGetIntegerCommand( p_vout, CFG_PREFIX "rows" );
214 p_vout->p_sys->i_cols =
215 var_CreateGetIntegerCommand( p_vout, CFG_PREFIX "cols" );
216 p_vout->p_sys->b_blackslot =
217 var_CreateGetBoolCommand( p_vout, CFG_PREFIX "black-slot" );
218 var_AddCallback( p_vout, CFG_PREFIX "rows",
219 PuzzleCallback, p_vout->p_sys );
220 var_AddCallback( p_vout, CFG_PREFIX "cols",
221 PuzzleCallback, p_vout->p_sys );
222 var_AddCallback( p_vout, CFG_PREFIX "black-slot",
223 PuzzleCallback, p_vout->p_sys );
225 p_vout->p_sys->pi_order = NULL;
226 shuffle( p_vout->p_sys );
228 p_vout->pf_init = Init;
229 p_vout->pf_end = End;
230 p_vout->pf_manage = NULL;
231 p_vout->pf_render = Render;
232 p_vout->pf_display = NULL;
233 p_vout->pf_control = Control;
238 /*****************************************************************************
239 * Init: initialize Magnify video thread output method
240 *****************************************************************************/
241 static int Init( vout_thread_t *p_vout )
244 memset( &fmt, 0, sizeof( video_format_t ) );
246 I_OUTPUTPICTURES = 0;
248 /* Initialize the output structure */
249 p_vout->output.i_chroma = p_vout->render.i_chroma;
250 p_vout->output.i_width = p_vout->render.i_width;
251 p_vout->output.i_height = p_vout->render.i_height;
252 p_vout->output.i_aspect = p_vout->render.i_aspect;
254 p_vout->fmt_out = p_vout->fmt_in;
255 fmt = p_vout->fmt_out;
257 /* Try to open the real video output */
258 msg_Dbg( p_vout, "spawning the real video output" );
260 p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
262 /* Everything failed */
263 if( p_vout->p_sys->p_vout == NULL )
265 msg_Err( p_vout, "cannot open vout, aborting" );
269 vout_filter_AllocateDirectBuffers( p_vout, VOUT_MAX_PICTURES );
271 vout_filter_AddChild( p_vout, p_vout->p_sys->p_vout, MouseEvent );
276 /*****************************************************************************
277 * End: terminate Magnify video thread output method
278 *****************************************************************************/
279 static void End( vout_thread_t *p_vout )
281 vout_sys_t *p_sys = p_vout->p_sys;
283 vout_filter_DelChild( p_vout, p_sys->p_vout, MouseEvent );
284 vout_CloseAndRelease( p_sys->p_vout );
286 vout_filter_ReleaseDirectBuffers( p_vout );
289 #define SHUFFLE_WIDTH 81
290 #define SHUFFLE_HEIGHT 13
291 static const char *shuffle_button[] =
293 ".................................................................................",
294 ".............. ............................ ........ ...... ...............",
295 ".............. ........................... ......... ........ ...............",
296 ".............. ........................... ......... ........ ...............",
297 ".. ....... . ....... .... ...... ...... ...... ........ ...",
298 ". .... ...... ... ...... .... ....... ......... ........ ....... .. ..",
299 ". ........... .... ...... .... ....... ......... ........ ...... .... .",
300 ". ....... .... ...... .... ....... ......... ........ ...... .",
301 ".. ...... .... ...... .... ....... ......... ........ ...... .......",
302 "...... ...... .... ...... .... ....... ......... ........ ...... .......",
303 ". .... ...... .... ...... ... ....... ......... ........ ....... .... .",
304 ".. ....... .... ....... . ....... ......... ........ ........ ..",
305 "................................................................................."};
308 /*****************************************************************************
309 * Destroy: destroy Magnify video thread output method
310 *****************************************************************************/
311 static void Destroy( vlc_object_t *p_this )
313 vout_thread_t *p_vout = (vout_thread_t *)p_this;
315 image_HandlerDelete( p_vout->p_sys->p_image );
316 free( p_vout->p_sys->pi_order );
318 free( p_vout->p_sys );
321 /*****************************************************************************
322 * Render: displays previously rendered output
323 *****************************************************************************/
324 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
328 //video_format_t fmt_out;
329 // memset( &fmt_out, 0, sizeof(video_format_t) );
330 //picture_t *p_converted;
334 int i_rows = p_vout->p_sys->i_rows;
335 int i_cols = p_vout->p_sys->i_cols;
337 /* This is a new frame. Get a structure from the video_output. */
338 while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
341 if( !vlc_object_alive (p_vout) || p_vout->b_error )
345 msleep( VOUT_OUTMEM_SLEEP );
348 p_outpic->date = p_pic->date;
350 for( i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
352 plane_t *p_in = p_pic->p+i_plane;
353 plane_t *p_out = p_outpic->p+i_plane;
354 int i_pitch = p_in->i_pitch;
357 for( i = 0; i < i_cols * i_rows; i++ )
359 int i_col = i % i_cols;
360 int i_row = i / i_cols;
361 int i_ocol = p_vout->p_sys->pi_order[i] % i_cols;
362 int i_orow = p_vout->p_sys->pi_order[i] / i_cols;
363 int i_last_row = i_row + 1;
364 i_orow *= p_in->i_lines / i_rows;
365 i_row *= p_in->i_lines / i_rows;
366 i_last_row *= p_in->i_lines / i_rows;
368 if( p_vout->p_sys->b_blackslot == true
369 && p_vout->p_sys->b_finished == false
370 && i == p_vout->p_sys->i_selected )
372 uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
373 for( ; i_row < i_last_row; i_row++, i_orow++ )
375 vlc_memset( p_out->p_pixels + i_row * i_pitch
376 + i_col * i_pitch / i_cols,
377 color, i_pitch / i_cols );
382 for( ; i_row < i_last_row; i_row++, i_orow++ )
384 vlc_memcpy( p_out->p_pixels + i_row * i_pitch
385 + i_col * i_pitch / i_cols,
386 p_in->p_pixels + i_orow * i_pitch
387 + i_ocol * i_pitch / i_cols,
394 if( p_vout->p_sys->i_selected != -1
395 && p_vout->p_sys->b_blackslot == false )
397 plane_t *p_in = p_pic->p+Y_PLANE;
398 plane_t *p_out = p_outpic->p+Y_PLANE;
399 int i_pitch = p_in->i_pitch;
400 int i_col = p_vout->p_sys->i_selected % i_cols;
401 int i_row = p_vout->p_sys->i_selected / i_cols;
402 int i_last_row = i_row + 1;
403 i_row *= p_in->i_lines / i_rows;
404 i_last_row *= p_in->i_lines / i_rows;
405 vlc_memset( p_out->p_pixels + i_row * i_pitch
406 + i_col * i_pitch / i_cols,
407 0xff, i_pitch / i_cols );
408 for( ; i_row < i_last_row; i_row++ )
410 p_out->p_pixels[ i_row * i_pitch
411 + i_col * i_pitch / i_cols ] = 0xff;
412 p_out->p_pixels[ i_row * i_pitch
413 + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
416 vlc_memset( p_out->p_pixels + i_row * i_pitch
417 + i_col * i_pitch / i_cols,
418 0xff, i_pitch / i_cols );
421 if( p_vout->p_sys->b_finished == true )
424 plane_t *p_out = p_outpic->p+Y_PLANE;
425 int i_pitch = p_out->i_pitch;
426 for( i = 0; i < SHUFFLE_HEIGHT; i++ )
428 for( j = 0; j < SHUFFLE_WIDTH; j++ )
430 if( shuffle_button[i][j] == '.' )
431 p_out->p_pixels[ i * i_pitch + j ] = 0xff;
436 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
439 /*****************************************************************************
440 * MouseEvent: callback for mouse events
441 *****************************************************************************/
442 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
443 vlc_value_t oldval, vlc_value_t newval, void *p_data )
445 vout_thread_t *p_vout = p_data;
446 VLC_UNUSED(p_this); VLC_UNUSED(oldval);
450 /* FIXME missing lock */
452 #define MOUSE_CLICKED 2
453 #define MOUSE_MOVE_X 4
454 #define MOUSE_MOVE_Y 8
455 #define MOUSE_MOVE 12
458 int v_h = p_vout->output.i_height;
459 int v_w = p_vout->output.i_width;
462 if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
463 if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
464 if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
466 i_v = var_GetInteger( p_vout->p_sys->p_vout, "mouse-button-down" );
467 if( i_v & 0x1 ) mouse |= MOUSE_DOWN;
468 i_y = var_GetInteger( p_vout->p_sys->p_vout, "mouse-y" );
469 i_x = var_GetInteger( p_vout->p_sys->p_vout, "mouse-x" );
471 if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
474 if( mouse & MOUSE_CLICKED )
476 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;
477 if( p_vout->p_sys->b_finished == true
478 && i_x < SHUFFLE_WIDTH && i_y < SHUFFLE_HEIGHT )
480 shuffle( p_vout->p_sys );
482 else if( p_vout->p_sys->i_selected == -1 )
484 p_vout->p_sys->i_selected = i_pos;
486 else if( p_vout->p_sys->i_selected == i_pos
487 && p_vout->p_sys->b_blackslot == false )
489 p_vout->p_sys->i_selected = -1;
491 else if( ( p_vout->p_sys->i_selected == i_pos + 1
492 && p_vout->p_sys->i_selected%p_vout->p_sys->i_cols != 0 )
493 || ( p_vout->p_sys->i_selected == i_pos - 1
494 && i_pos % p_vout->p_sys->i_cols != 0 )
495 || p_vout->p_sys->i_selected == i_pos + p_vout->p_sys->i_cols
496 || p_vout->p_sys->i_selected == i_pos - p_vout->p_sys->i_cols )
498 int a = p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ];
499 p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ] =
500 p_vout->p_sys->pi_order[ i_pos ];
501 p_vout->p_sys->pi_order[ i_pos ] = a;
502 if( p_vout->p_sys->b_blackslot == true )
503 p_vout->p_sys->i_selected = i_pos;
505 p_vout->p_sys->i_selected = -1;
507 p_vout->p_sys->b_finished = finished( p_vout->p_sys );
510 /* FIXME do we want to forward it or not ? */
511 var_Set( p_vout, psz_var, newval );
515 static int PuzzleCallback( vlc_object_t *p_this, char const *psz_var,
516 vlc_value_t oldval, vlc_value_t newval,
519 VLC_UNUSED(p_this); VLC_UNUSED(oldval);
520 vout_sys_t *p_sys = (vout_sys_t *)p_data;
521 if( !strcmp( psz_var, CFG_PREFIX "rows" ) )
523 p_sys->i_rows = __MAX( 1, newval.i_int );
525 else if( !strcmp( psz_var, CFG_PREFIX "cols" ) )
527 p_sys->i_cols = __MAX( 1, newval.i_int );
529 else if( !strcmp( psz_var, CFG_PREFIX "black-slot" ) )
531 p_sys->b_blackslot = newval.b_bool;