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 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
35 #include "filter_common.h"
36 #include "vlc_image.h"
37 #include "vlc_input.h"
38 #include "vlc_playlist.h"
40 /*****************************************************************************
42 *****************************************************************************/
43 static int Create ( vlc_object_t * );
44 static void Destroy ( vlc_object_t * );
46 static int Init ( vout_thread_t * );
47 static void End ( vout_thread_t * );
48 static void Render ( vout_thread_t *, picture_t * );
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 * );
55 /*****************************************************************************
57 *****************************************************************************/
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.")
66 #define CFG_PREFIX "puzzle-"
69 set_description( _("Puzzle interactive game video filter") );
70 set_shortname( _( "Puzzle" ));
71 set_capability( "video filter", 0 );
72 set_category( CAT_VIDEO );
73 set_subcategory( SUBCAT_VIDEO_VFILTER );
75 add_integer_with_range( CFG_PREFIX "rows", 4, 1, 128, NULL,
76 ROWS_TEXT, ROWS_LONGTEXT, VLC_FALSE );
77 add_integer_with_range( CFG_PREFIX "cols", 4, 1, 128, NULL,
78 COLS_TEXT, COLS_LONGTEXT, VLC_FALSE );
79 add_bool( CFG_PREFIX "black-slot", 0, NULL,
80 BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, VLC_FALSE );
82 set_callbacks( Create, Destroy );
85 static const char *ppsz_filter_options[] = {
86 "rows", "cols", "black-slot", NULL
89 /*****************************************************************************
90 * vout_sys_t: Magnify video output method descriptor
91 *****************************************************************************/
94 vout_thread_t *p_vout;
96 image_handler_t *p_image;
102 vlc_bool_t b_finished;
104 vlc_bool_t b_blackslot;
107 /*****************************************************************************
108 * Control: control facility for the vout (forwards to child vout)
109 *****************************************************************************/
110 static int Control( vout_thread_t *p_vout, int i_query, va_list args )
112 return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
115 /*****************************************************************************
117 *****************************************************************************/
118 static vlc_bool_t finished( vout_sys_t *p_sys )
121 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
123 if( i != p_sys->pi_order[i] ) return VLC_FALSE;
127 static vlc_bool_t is_valid( vout_sys_t *p_sys )
130 if( p_sys->b_blackslot == VLC_FALSE ) return VLC_TRUE;
131 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
133 if( p_sys->pi_order[i] == p_sys->i_cols * p_sys->i_rows - 1 )
135 d += i / p_sys->i_cols + 1;
138 for( j = i+1; j < p_sys->i_cols * p_sys->i_rows; j++ )
140 if( p_sys->pi_order[j] == p_sys->i_cols * p_sys->i_rows - 1 )
142 if( p_sys->pi_order[i] > p_sys->pi_order[j] ) d++;
145 if( d%2!=0 ) return VLC_FALSE;
146 else return VLC_TRUE;
148 static void shuffle( vout_sys_t *p_sys )
151 free( p_sys->pi_order );
152 p_sys->pi_order = malloc( p_sys->i_cols * p_sys->i_rows * sizeof( int ) );
155 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
157 p_sys->pi_order[i] = -1;
160 for( c = 0; c < p_sys->i_cols * p_sys->i_rows; )
162 i = rand()%( p_sys->i_cols * p_sys->i_rows );
163 if( p_sys->pi_order[i] == -1 )
165 p_sys->pi_order[i] = c;
169 p_sys->b_finished = finished( p_sys );
170 } while( p_sys->b_finished == VLC_TRUE
171 || is_valid( p_sys ) == VLC_FALSE );
173 if( p_sys->b_blackslot == VLC_TRUE )
175 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
177 if( p_sys->pi_order[i] ==
178 p_sys->i_cols * p_sys->i_rows - 1 )
180 p_sys->i_selected = i;
187 p_sys->i_selected = -1;
191 /*****************************************************************************
192 * Create: allocates Magnify video thread output method
193 *****************************************************************************/
194 static int Create( vlc_object_t *p_this )
196 vout_thread_t *p_vout = (vout_thread_t *)p_this;
198 /* Allocate structure */
199 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
200 if( p_vout->p_sys == NULL )
202 msg_Err( p_vout, "out of memory" );
206 p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
208 config_ChainParse( p_vout, CFG_PREFIX, ppsz_filter_options,
211 p_vout->p_sys->i_rows = var_CreateGetInteger( p_vout, CFG_PREFIX "rows" );
212 p_vout->p_sys->i_cols = var_CreateGetInteger( p_vout, CFG_PREFIX "cols" );
213 p_vout->p_sys->b_blackslot =
214 var_CreateGetInteger( p_vout, CFG_PREFIX "black-slot" );
216 p_vout->p_sys->pi_order = NULL;
217 shuffle( p_vout->p_sys );
219 p_vout->pf_init = Init;
220 p_vout->pf_end = End;
221 p_vout->pf_manage = NULL;
222 p_vout->pf_render = Render;
223 p_vout->pf_display = NULL;
224 p_vout->pf_control = Control;
229 /*****************************************************************************
230 * Init: initialize Magnify video thread output method
231 *****************************************************************************/
232 static int Init( vout_thread_t *p_vout )
236 video_format_t fmt = {0};
238 I_OUTPUTPICTURES = 0;
240 /* Initialize the output structure */
241 p_vout->output.i_chroma = p_vout->render.i_chroma;
242 p_vout->output.i_width = p_vout->render.i_width;
243 p_vout->output.i_height = p_vout->render.i_height;
244 p_vout->output.i_aspect = p_vout->render.i_aspect;
246 p_vout->fmt_out = p_vout->fmt_in;
247 fmt = p_vout->fmt_out;
249 /* Try to open the real video output */
250 msg_Dbg( p_vout, "spawning the real video output" );
252 p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
254 /* Everything failed */
255 if( p_vout->p_sys->p_vout == NULL )
257 msg_Err( p_vout, "cannot open vout, aborting" );
261 var_AddCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout );
262 var_AddCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout );
263 var_AddCallback( p_vout->p_sys->p_vout, "mouse-clicked",
266 ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
267 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
268 ADD_PARENT_CALLBACKS( SendEventsToChild );
273 /*****************************************************************************
274 * End: terminate Magnify video thread output method
275 *****************************************************************************/
276 static void End( vout_thread_t *p_vout )
280 /* Free the fake output buffers we allocated */
281 for( i_index = I_OUTPUTPICTURES ; i_index ; )
284 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
287 var_DelCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout);
288 var_DelCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout);
289 var_DelCallback( p_vout->p_sys->p_vout, "mouse-clicked", MouseEvent, p_vout);
292 #define SHUFFLE_WIDTH 81
293 #define SHUFFLE_HEIGHT 13
294 static const char *shuffle_button[] =
296 ".................................................................................",
297 ".............. ............................ ........ ...... ...............",
298 ".............. ........................... ......... ........ ...............",
299 ".............. ........................... ......... ........ ...............",
300 ".. ....... . ....... .... ...... ...... ...... ........ ...",
301 ". .... ...... ... ...... .... ....... ......... ........ ....... .. ..",
302 ". ........... .... ...... .... ....... ......... ........ ...... .... .",
303 ". ....... .... ...... .... ....... ......... ........ ...... .",
304 ".. ...... .... ...... .... ....... ......... ........ ...... .......",
305 "...... ...... .... ...... .... ....... ......... ........ ...... .......",
306 ". .... ...... .... ...... ... ....... ......... ........ ....... .... .",
307 ".. ....... .... ....... . ....... ......... ........ ........ ..",
308 "................................................................................."};
311 /*****************************************************************************
312 * Destroy: destroy Magnify video thread output method
313 *****************************************************************************/
314 static void Destroy( vlc_object_t *p_this )
316 vout_thread_t *p_vout = (vout_thread_t *)p_this;
318 if( p_vout->p_sys->p_vout )
320 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
321 vlc_object_detach( p_vout->p_sys->p_vout );
322 vout_Destroy( p_vout->p_sys->p_vout );
325 image_HandlerDelete( p_vout->p_sys->p_image );
326 free( p_vout->p_sys->pi_order );
328 DEL_PARENT_CALLBACKS( SendEventsToChild );
330 free( p_vout->p_sys );
333 /*****************************************************************************
334 * Render: displays previously rendered output
335 *****************************************************************************/
336 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
340 //video_format_t fmt_out = {0};
341 //picture_t *p_converted;
345 int i_rows = p_vout->p_sys->i_rows;
346 int i_cols = p_vout->p_sys->i_cols;
348 /* This is a new frame. Get a structure from the video_output. */
349 while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
352 if( p_vout->b_die || p_vout->b_error )
356 msleep( VOUT_OUTMEM_SLEEP );
359 vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
361 for( i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
363 plane_t *p_in = p_pic->p+i_plane;
364 plane_t *p_out = p_outpic->p+i_plane;
365 int i_pitch = p_in->i_pitch;
368 for( i = 0; i < i_cols * i_rows; i++ )
370 int i_col = i % i_cols;
371 int i_row = i / i_cols;
372 int i_ocol = p_vout->p_sys->pi_order[i] % i_cols;
373 int i_orow = p_vout->p_sys->pi_order[i] / i_cols;
374 int i_last_row = i_row + 1;
375 i_orow *= p_in->i_lines / i_rows;
376 i_row *= p_in->i_lines / i_rows;
377 i_last_row *= p_in->i_lines / i_rows;
379 if( p_vout->p_sys->b_blackslot == VLC_TRUE
380 && p_vout->p_sys->b_finished == VLC_FALSE
381 && i == p_vout->p_sys->i_selected )
383 uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
384 for( ; i_row < i_last_row; i_row++, i_orow++ )
387 pf_memset( p_out->p_pixels + i_row * i_pitch
388 + i_col * i_pitch / i_cols,
389 color, i_pitch / i_cols );
394 for( ; i_row < i_last_row; i_row++, i_orow++ )
397 pf_memcpy( p_out->p_pixels + i_row * i_pitch
398 + i_col * i_pitch / i_cols,
399 p_in->p_pixels + i_orow * i_pitch
400 + i_ocol * i_pitch / i_cols,
407 if( p_vout->p_sys->i_selected != -1
408 && p_vout->p_sys->b_blackslot == VLC_FALSE )
410 plane_t *p_in = p_pic->p+Y_PLANE;
411 plane_t *p_out = p_outpic->p+Y_PLANE;
412 int i_pitch = p_in->i_pitch;
413 int i_col = p_vout->p_sys->i_selected % i_cols;
414 int i_row = p_vout->p_sys->i_selected / i_cols;
415 int i_last_row = i_row + 1;
416 i_row *= p_in->i_lines / i_rows;
417 i_last_row *= p_in->i_lines / i_rows;
419 pf_memset( p_out->p_pixels + i_row * i_pitch
420 + i_col * i_pitch / i_cols,
421 0xff, i_pitch / i_cols );
422 for( ; i_row < i_last_row; i_row++ )
424 p_out->p_pixels[ i_row * i_pitch
425 + i_col * i_pitch / i_cols ] = 0xff;
426 p_out->p_pixels[ i_row * i_pitch
427 + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
431 pf_memset( p_out->p_pixels + i_row * i_pitch
432 + i_col * i_pitch / i_cols,
433 0xff, i_pitch / i_cols );
436 if( p_vout->p_sys->b_finished == VLC_TRUE )
439 plane_t *p_out = p_outpic->p+Y_PLANE;
440 int i_pitch = p_out->i_pitch;
441 for( i = 0; i < SHUFFLE_HEIGHT; i++ )
443 for( j = 0; j < SHUFFLE_WIDTH; j++ )
445 if( shuffle_button[i][j] == '.' )
446 p_out->p_pixels[ i * i_pitch + j ] = 0xff;
451 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
454 /*****************************************************************************
455 * SendEvents: forward mouse and keyboard events to the parent p_vout
456 *****************************************************************************/
457 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
458 vlc_value_t oldval, vlc_value_t newval, void *p_data )
460 var_Set( (vlc_object_t *)p_data, psz_var, newval );
465 /*****************************************************************************
466 * SendEventsToChild: forward events to the child/children vout
467 *****************************************************************************/
468 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
469 vlc_value_t oldval, vlc_value_t newval, void *p_data )
471 vout_thread_t *p_vout = (vout_thread_t *)p_this;
472 var_Set( p_vout->p_sys->p_vout, psz_var, newval );
476 /*****************************************************************************
477 * MouseEvent: callback for mouse events
478 *****************************************************************************/
479 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
480 vlc_value_t oldval, vlc_value_t newval, void *p_data )
482 vout_thread_t *p_vout = (vout_thread_t*)p_data;
487 #define MOUSE_CLICKED 2
488 #define MOUSE_MOVE_X 4
489 #define MOUSE_MOVE_Y 8
490 #define MOUSE_MOVE 12
493 int v_h = p_vout->output.i_height;
494 int v_w = p_vout->output.i_width;
497 if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
498 if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
499 if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
501 i_v = var_GetInteger( p_vout->p_sys->p_vout, "mouse-button-down" );
502 if( i_v & 0x1 ) mouse |= MOUSE_DOWN;
503 i_y = var_GetInteger( p_vout->p_sys->p_vout, "mouse-y" );
504 i_x = var_GetInteger( p_vout->p_sys->p_vout, "mouse-x" );
506 if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
509 if( mouse & MOUSE_CLICKED )
511 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;
512 if( p_vout->p_sys->b_finished == VLC_TRUE
513 && i_x < SHUFFLE_WIDTH && i_y < SHUFFLE_HEIGHT )
515 shuffle( p_vout->p_sys );
517 else if( p_vout->p_sys->i_selected == -1 )
519 p_vout->p_sys->i_selected = i_pos;
521 else if( p_vout->p_sys->i_selected == i_pos
522 && p_vout->p_sys->b_blackslot == VLC_FALSE )
524 p_vout->p_sys->i_selected = -1;
526 else if( ( p_vout->p_sys->i_selected == i_pos + 1
527 && p_vout->p_sys->i_selected%p_vout->p_sys->i_cols != 0 )
528 || ( p_vout->p_sys->i_selected == i_pos - 1
529 && i_pos % p_vout->p_sys->i_cols != 0 )
530 || p_vout->p_sys->i_selected == i_pos + p_vout->p_sys->i_cols
531 || p_vout->p_sys->i_selected == i_pos - p_vout->p_sys->i_cols )
533 int a = p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ];
534 p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ] =
535 p_vout->p_sys->pi_order[ i_pos ];
536 p_vout->p_sys->pi_order[ i_pos ] = a;
537 if( p_vout->p_sys->b_blackslot == VLC_TRUE )
538 p_vout->p_sys->i_selected = i_pos;
540 p_vout->p_sys->i_selected = -1;
542 p_vout->p_sys->b_finished = finished( p_vout->p_sys );