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.")
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 );
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 );
80 set_callbacks( Create, Destroy );
83 /*****************************************************************************
84 * vout_sys_t: Magnify video output method descriptor
85 *****************************************************************************/
88 vout_thread_t *p_vout;
90 image_handler_t *p_image;
96 vlc_bool_t b_finished;
98 vlc_bool_t b_blackslot;
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 )
106 return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
109 /*****************************************************************************
111 *****************************************************************************/
112 static vlc_bool_t finished( vout_sys_t *p_sys )
115 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
117 if( i != p_sys->pi_order[i] ) return VLC_FALSE;
121 static vlc_bool_t is_valid( vout_sys_t *p_sys )
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++ )
127 if( p_sys->pi_order[i] == p_sys->i_cols * p_sys->i_rows - 1 )
129 d += i / p_sys->i_cols + 1;
132 for( j = i+1; j < p_sys->i_cols * p_sys->i_rows; j++ )
134 if( p_sys->pi_order[j] == p_sys->i_cols * p_sys->i_rows - 1 )
136 if( p_sys->pi_order[i] > p_sys->pi_order[j] ) d++;
139 if( d%2!=0 ) return VLC_FALSE;
140 else return VLC_TRUE;
142 static void shuffle( vout_sys_t *p_sys )
145 free( p_sys->pi_order );
146 p_sys->pi_order = malloc( p_sys->i_cols * p_sys->i_rows * sizeof( int ) );
149 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
151 p_sys->pi_order[i] = -1;
154 for( c = 0; c < p_sys->i_cols * p_sys->i_rows; )
156 i = rand()%( p_sys->i_cols * p_sys->i_rows );
157 if( p_sys->pi_order[i] == -1 )
159 p_sys->pi_order[i] = c;
163 p_sys->b_finished = finished( p_sys );
164 } while( p_sys->b_finished == VLC_TRUE
165 || is_valid( p_sys ) == VLC_FALSE );
167 if( p_sys->b_blackslot == VLC_TRUE )
169 for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
171 if( p_sys->pi_order[i] ==
172 p_sys->i_cols * p_sys->i_rows - 1 )
174 p_sys->i_selected = i;
181 p_sys->i_selected = -1;
185 /*****************************************************************************
186 * Create: allocates Magnify video thread output method
187 *****************************************************************************/
188 static int Create( vlc_object_t *p_this )
190 vout_thread_t *p_vout = (vout_thread_t *)p_this;
192 /* Allocate structure */
193 p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
194 if( p_vout->p_sys == NULL )
196 msg_Err( p_vout, "out of memory" );
200 p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
202 p_vout->p_sys->i_rows = config_GetInt( p_vout, "puzzle-rows" );
203 p_vout->p_sys->i_cols = config_GetInt( p_vout, "puzzle-cols" );
204 p_vout->p_sys->b_blackslot = config_GetInt( p_vout, "puzzle-black-slot" );
206 p_vout->p_sys->pi_order = NULL;
207 shuffle( p_vout->p_sys );
209 p_vout->pf_init = Init;
210 p_vout->pf_end = End;
211 p_vout->pf_manage = NULL;
212 p_vout->pf_render = Render;
213 p_vout->pf_display = NULL;
214 p_vout->pf_control = Control;
219 /*****************************************************************************
220 * Init: initialize Magnify video thread output method
221 *****************************************************************************/
222 static int Init( vout_thread_t *p_vout )
226 video_format_t fmt = {0};
228 I_OUTPUTPICTURES = 0;
230 /* Initialize the output structure */
231 p_vout->output.i_chroma = p_vout->render.i_chroma;
232 p_vout->output.i_width = p_vout->render.i_width;
233 p_vout->output.i_height = p_vout->render.i_height;
234 p_vout->output.i_aspect = p_vout->render.i_aspect;
236 p_vout->fmt_out = p_vout->fmt_in;
237 fmt = p_vout->fmt_out;
239 /* Try to open the real video output */
240 msg_Dbg( p_vout, "spawning the real video output" );
242 p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
244 /* Everything failed */
245 if( p_vout->p_sys->p_vout == NULL )
247 msg_Err( p_vout, "cannot open vout, aborting" );
251 var_AddCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout );
252 var_AddCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout );
253 var_AddCallback( p_vout->p_sys->p_vout, "mouse-clicked",
256 ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
257 ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
258 ADD_PARENT_CALLBACKS( SendEventsToChild );
263 /*****************************************************************************
264 * End: terminate Magnify video thread output method
265 *****************************************************************************/
266 static void End( vout_thread_t *p_vout )
270 /* Free the fake output buffers we allocated */
271 for( i_index = I_OUTPUTPICTURES ; i_index ; )
274 free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
277 var_DelCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout);
278 var_DelCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout);
279 var_DelCallback( p_vout->p_sys->p_vout, "mouse-clicked", MouseEvent, p_vout);
282 #define SHUFFLE_WIDTH 81
283 #define SHUFFLE_HEIGHT 13
284 static const char *shuffle_button[] =
286 ".................................................................................",
287 ".............. ............................ ........ ...... ...............",
288 ".............. ........................... ......... ........ ...............",
289 ".............. ........................... ......... ........ ...............",
290 ".. ....... . ....... .... ...... ...... ...... ........ ...",
291 ". .... ...... ... ...... .... ....... ......... ........ ....... .. ..",
292 ". ........... .... ...... .... ....... ......... ........ ...... .... .",
293 ". ....... .... ...... .... ....... ......... ........ ...... .",
294 ".. ...... .... ...... .... ....... ......... ........ ...... .......",
295 "...... ...... .... ...... .... ....... ......... ........ ...... .......",
296 ". .... ...... .... ...... ... ....... ......... ........ ....... .... .",
297 ".. ....... .... ....... . ....... ......... ........ ........ ..",
298 "................................................................................."};
301 /*****************************************************************************
302 * Destroy: destroy Magnify video thread output method
303 *****************************************************************************/
304 static void Destroy( vlc_object_t *p_this )
306 vout_thread_t *p_vout = (vout_thread_t *)p_this;
308 if( p_vout->p_sys->p_vout )
310 DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
311 vlc_object_detach( p_vout->p_sys->p_vout );
312 vout_Destroy( p_vout->p_sys->p_vout );
315 image_HandlerDelete( p_vout->p_sys->p_image );
316 free( p_vout->p_sys->pi_order );
318 DEL_PARENT_CALLBACKS( SendEventsToChild );
320 free( p_vout->p_sys );
323 /*****************************************************************************
324 * Render: displays previously rendered output
325 *****************************************************************************/
326 static void Render( vout_thread_t *p_vout, picture_t *p_pic )
330 //video_format_t fmt_out = {0};
331 //picture_t *p_converted;
335 int i_rows = p_vout->p_sys->i_rows;
336 int i_cols = p_vout->p_sys->i_cols;
338 /* This is a new frame. Get a structure from the video_output. */
339 while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
342 if( p_vout->b_die || p_vout->b_error )
346 msleep( VOUT_OUTMEM_SLEEP );
349 vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
351 for( i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
353 plane_t *p_in = p_pic->p+i_plane;
354 plane_t *p_out = p_outpic->p+i_plane;
355 int i_pitch = p_in->i_pitch;
358 for( i = 0; i < i_cols * i_rows; i++ )
360 int i_col = i % i_cols;
361 int i_row = i / i_cols;
362 int i_ocol = p_vout->p_sys->pi_order[i] % i_cols;
363 int i_orow = p_vout->p_sys->pi_order[i] / i_cols;
364 int i_last_row = i_row + 1;
365 i_orow *= p_in->i_lines / i_rows;
366 i_row *= p_in->i_lines / i_rows;
367 i_last_row *= p_in->i_lines / i_rows;
369 if( p_vout->p_sys->b_blackslot == VLC_TRUE
370 && p_vout->p_sys->b_finished == VLC_FALSE
371 && i == p_vout->p_sys->i_selected )
373 uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
374 for( ; i_row < i_last_row; i_row++, i_orow++ )
377 pf_memset( p_out->p_pixels + i_row * i_pitch
378 + i_col * i_pitch / i_cols,
379 color, i_pitch / i_cols );
384 for( ; i_row < i_last_row; i_row++, i_orow++ )
387 pf_memcpy( p_out->p_pixels + i_row * i_pitch
388 + i_col * i_pitch / i_cols,
389 p_in->p_pixels + i_orow * i_pitch
390 + i_ocol * i_pitch / i_cols,
397 if( p_vout->p_sys->i_selected != -1
398 && p_vout->p_sys->b_blackslot == VLC_FALSE )
400 plane_t *p_in = p_pic->p+Y_PLANE;
401 plane_t *p_out = p_outpic->p+Y_PLANE;
402 int i_pitch = p_in->i_pitch;
403 int i_col = p_vout->p_sys->i_selected % i_cols;
404 int i_row = p_vout->p_sys->i_selected / i_cols;
405 int i_last_row = i_row + 1;
406 i_row *= p_in->i_lines / i_rows;
407 i_last_row *= p_in->i_lines / i_rows;
409 pf_memset( p_out->p_pixels + i_row * i_pitch
410 + i_col * i_pitch / i_cols,
411 0xff, i_pitch / i_cols );
412 for( ; i_row < i_last_row; i_row++ )
414 p_out->p_pixels[ i_row * i_pitch
415 + i_col * i_pitch / i_cols ] = 0xff;
416 p_out->p_pixels[ i_row * i_pitch
417 + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
421 pf_memset( p_out->p_pixels + i_row * i_pitch
422 + i_col * i_pitch / i_cols,
423 0xff, i_pitch / i_cols );
426 if( p_vout->p_sys->b_finished == VLC_TRUE )
429 plane_t *p_out = p_outpic->p+Y_PLANE;
430 int i_pitch = p_out->i_pitch;
431 for( i = 0; i < SHUFFLE_HEIGHT; i++ )
433 for( j = 0; j < SHUFFLE_WIDTH; j++ )
435 if( shuffle_button[i][j] == '.' )
436 p_out->p_pixels[ i * i_pitch + j ] = 0xff;
441 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
444 /*****************************************************************************
445 * SendEvents: forward mouse and keyboard events to the parent p_vout
446 *****************************************************************************/
447 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
448 vlc_value_t oldval, vlc_value_t newval, void *p_data )
450 var_Set( (vlc_object_t *)p_data, psz_var, newval );
455 /*****************************************************************************
456 * SendEventsToChild: forward events to the child/children vout
457 *****************************************************************************/
458 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
459 vlc_value_t oldval, vlc_value_t newval, void *p_data )
461 vout_thread_t *p_vout = (vout_thread_t *)p_this;
462 var_Set( p_vout->p_sys->p_vout, psz_var, newval );
466 /*****************************************************************************
467 * MouseEvent: callback for mouse events
468 *****************************************************************************/
469 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
470 vlc_value_t oldval, vlc_value_t newval, void *p_data )
472 vout_thread_t *p_vout = (vout_thread_t*)p_data;
477 #define MOUSE_CLICKED 2
478 #define MOUSE_MOVE_X 4
479 #define MOUSE_MOVE_Y 8
480 #define MOUSE_MOVE 12
483 int v_h = p_vout->output.i_height;
484 int v_w = p_vout->output.i_width;
487 if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
488 if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
489 if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
491 i_v = var_GetInteger( p_vout->p_sys->p_vout, "mouse-button-down" );
492 if( i_v & 0x1 ) mouse |= MOUSE_DOWN;
493 i_y = var_GetInteger( p_vout->p_sys->p_vout, "mouse-y" );
494 i_x = var_GetInteger( p_vout->p_sys->p_vout, "mouse-x" );
496 if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
499 if( mouse & MOUSE_CLICKED )
501 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;
502 if( p_vout->p_sys->b_finished == VLC_TRUE
503 && i_x < SHUFFLE_WIDTH && i_y < SHUFFLE_HEIGHT )
505 shuffle( p_vout->p_sys );
507 else if( p_vout->p_sys->i_selected == -1 )
509 p_vout->p_sys->i_selected = i_pos;
511 else if( p_vout->p_sys->i_selected == i_pos
512 && p_vout->p_sys->b_blackslot == VLC_FALSE )
514 p_vout->p_sys->i_selected = -1;
516 else if( ( p_vout->p_sys->i_selected == i_pos + 1
517 && p_vout->p_sys->i_selected%p_vout->p_sys->i_cols != 0 )
518 || ( p_vout->p_sys->i_selected == i_pos - 1
519 && i_pos % p_vout->p_sys->i_cols != 0 )
520 || p_vout->p_sys->i_selected == i_pos + p_vout->p_sys->i_cols
521 || p_vout->p_sys->i_selected == i_pos - p_vout->p_sys->i_cols )
523 int a = p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ];
524 p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ] =
525 p_vout->p_sys->pi_order[ i_pos ];
526 p_vout->p_sys->pi_order[ i_pos ] = a;
527 if( p_vout->p_sys->b_blackslot == VLC_TRUE )
528 p_vout->p_sys->i_selected = i_pos;
530 p_vout->p_sys->i_selected = -1;
532 p_vout->p_sys->b_finished = finished( p_vout->p_sys );