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 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++ )
376 memset( p_out->p_pixels + i_row * i_pitch
377 + i_col * i_pitch / i_cols,
378 color, i_pitch / i_cols );
383 for( ; i_row < i_last_row; i_row++, i_orow++ )
385 memcpy( p_out->p_pixels + i_row * i_pitch
386 + i_col * i_pitch / i_cols,
387 p_in->p_pixels + i_orow * i_pitch
388 + i_ocol * i_pitch / i_cols,
395 if( p_vout->p_sys->i_selected != -1
396 && p_vout->p_sys->b_blackslot == VLC_FALSE )
398 plane_t *p_in = p_pic->p+Y_PLANE;
399 plane_t *p_out = p_outpic->p+Y_PLANE;
400 int i_pitch = p_in->i_pitch;
401 int i_col = p_vout->p_sys->i_selected % i_cols;
402 int i_row = p_vout->p_sys->i_selected / i_cols;
403 int i_last_row = i_row + 1;
404 i_row *= p_in->i_lines / i_rows;
405 i_last_row *= p_in->i_lines / i_rows;
406 memset( p_out->p_pixels + i_row * i_pitch
407 + i_col * i_pitch / i_cols,
408 0xff, i_pitch / i_cols );
409 for( ; i_row < i_last_row; i_row++ )
411 p_out->p_pixels[ i_row * i_pitch
412 + i_col * i_pitch / i_cols ] = 0xff;
413 p_out->p_pixels[ i_row * i_pitch
414 + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
417 memset( p_out->p_pixels + i_row * i_pitch
418 + i_col * i_pitch / i_cols,
419 0xff, i_pitch / i_cols );
422 if( p_vout->p_sys->b_finished == VLC_TRUE )
425 plane_t *p_out = p_outpic->p+Y_PLANE;
426 int i_pitch = p_out->i_pitch;
427 for( i = 0; i < SHUFFLE_HEIGHT; i++ )
429 for( j = 0; j < SHUFFLE_WIDTH; j++ )
431 if( shuffle_button[i][j] == '.' )
432 p_out->p_pixels[ i * i_pitch + j ] = 0xff;
437 vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
440 /*****************************************************************************
441 * SendEvents: forward mouse and keyboard events to the parent p_vout
442 *****************************************************************************/
443 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
444 vlc_value_t oldval, vlc_value_t newval, void *p_data )
446 var_Set( (vlc_object_t *)p_data, psz_var, newval );
451 /*****************************************************************************
452 * SendEventsToChild: forward events to the child/children vout
453 *****************************************************************************/
454 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
455 vlc_value_t oldval, vlc_value_t newval, void *p_data )
457 vout_thread_t *p_vout = (vout_thread_t *)p_this;
458 var_Set( p_vout->p_sys->p_vout, psz_var, newval );
462 /*****************************************************************************
463 * MouseEvent: callback for mouse events
464 *****************************************************************************/
465 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
466 vlc_value_t oldval, vlc_value_t newval, void *p_data )
468 vout_thread_t *p_vout = (vout_thread_t*)p_data;
473 #define MOUSE_CLICKED 2
474 #define MOUSE_MOVE_X 4
475 #define MOUSE_MOVE_Y 8
476 #define MOUSE_MOVE 12
479 int v_h = p_vout->output.i_height;
480 int v_w = p_vout->output.i_width;
483 if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
484 if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
485 if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
487 i_v = var_GetInteger( p_vout->p_sys->p_vout, "mouse-button-down" );
488 if( i_v & 0x1 ) mouse |= MOUSE_DOWN;
489 i_y = var_GetInteger( p_vout->p_sys->p_vout, "mouse-y" );
490 i_x = var_GetInteger( p_vout->p_sys->p_vout, "mouse-x" );
492 if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
495 if( mouse & MOUSE_CLICKED )
497 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;
498 if( p_vout->p_sys->b_finished == VLC_TRUE
499 && i_x < SHUFFLE_WIDTH && i_y < SHUFFLE_HEIGHT )
501 shuffle( p_vout->p_sys );
503 else if( p_vout->p_sys->i_selected == -1 )
505 p_vout->p_sys->i_selected = i_pos;
507 else if( p_vout->p_sys->i_selected == i_pos
508 && p_vout->p_sys->b_blackslot == VLC_FALSE )
510 p_vout->p_sys->i_selected = -1;
512 else if( ( p_vout->p_sys->i_selected == i_pos + 1
513 && p_vout->p_sys->i_selected%p_vout->p_sys->i_cols != 0 )
514 || ( p_vout->p_sys->i_selected == i_pos - 1
515 && i_pos % p_vout->p_sys->i_cols != 0 )
516 || p_vout->p_sys->i_selected == i_pos + p_vout->p_sys->i_cols
517 || p_vout->p_sys->i_selected == i_pos - p_vout->p_sys->i_cols )
519 int a = p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ];
520 p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ] =
521 p_vout->p_sys->pi_order[ i_pos ];
522 p_vout->p_sys->pi_order[ i_pos ] = a;
523 if( p_vout->p_sys->b_blackslot == VLC_TRUE )
524 p_vout->p_sys->i_selected = i_pos;
526 p_vout->p_sys->i_selected = -1;
528 p_vout->p_sys->b_finished = finished( p_vout->p_sys );