/*****************************************************************************
* puzzle.c : Puzzle game
*****************************************************************************
- * Copyright (C) 2005-2006 the VideoLAN team
+ * Copyright (C) 2005-2009 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
-
-#include <vlc/vlc.h>
-#include <vlc_vout.h>
-
#include <math.h>
-#include "filter_common.h"
-#include "vlc_image.h"
-#include "vlc_input.h"
-#include "vlc_playlist.h"
-
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-static int Create ( vlc_object_t * );
-static void Destroy ( vlc_object_t * );
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_filter.h>
+#include <vlc_rand.h>
-static int Init ( vout_thread_t * );
-static void End ( vout_thread_t * );
-static void Render ( vout_thread_t *, picture_t * );
-
-static int SendEvents ( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
-static int MouseEvent ( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
-
-static int PuzzleCallback( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
+#include "filter_picture.h"
/*****************************************************************************
* Module descriptor
*****************************************************************************/
-
#define ROWS_TEXT N_("Number of puzzle rows")
#define ROWS_LONGTEXT N_("Number of puzzle rows")
#define COLS_TEXT N_("Number of puzzle columns")
#define CFG_PREFIX "puzzle-"
-vlc_module_begin();
- set_description( _("Puzzle interactive game video filter") );
- set_shortname( _( "Puzzle" ));
- set_capability( "video filter", 0 );
- set_category( CAT_VIDEO );
- set_subcategory( SUBCAT_VIDEO_VFILTER );
+static int Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
- add_integer_with_range( CFG_PREFIX "rows", 4, 1, 128, NULL,
- ROWS_TEXT, ROWS_LONGTEXT, false );
- add_integer_with_range( CFG_PREFIX "cols", 4, 1, 128, NULL,
- COLS_TEXT, COLS_LONGTEXT, false );
- add_bool( CFG_PREFIX "black-slot", 0, NULL,
- BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, false );
+vlc_module_begin()
+ set_description( N_("Puzzle interactive game video filter") )
+ set_shortname( N_( "Puzzle" ))
+ set_capability( "video filter2", 0 )
+ set_category( CAT_VIDEO )
+ set_subcategory( SUBCAT_VIDEO_VFILTER )
- set_callbacks( Create, Destroy );
-vlc_module_end();
+ add_integer_with_range( CFG_PREFIX "rows", 4, 2, 16, NULL,
+ ROWS_TEXT, ROWS_LONGTEXT, false )
+ add_integer_with_range( CFG_PREFIX "cols", 4, 2, 16, NULL,
+ COLS_TEXT, COLS_LONGTEXT, false )
+ add_bool( CFG_PREFIX "black-slot", false, NULL,
+ BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, false )
+
+ set_callbacks( Open, Close )
+vlc_module_end()
-static const char *ppsz_filter_options[] = {
- "rows", "cols", "black-slot", NULL
-};
/*****************************************************************************
- * vout_sys_t: Magnify video output method descriptor
+ * Local prototypes
*****************************************************************************/
-struct vout_sys_t
-{
- vout_thread_t *p_vout;
+static const char *const ppsz_filter_options[] = {
+ "rows", "cols", "black-slot", NULL
+};
+
+static picture_t *Filter( filter_t *, picture_t * );
+static int Mouse( filter_t *, vlc_mouse_t *, const vlc_mouse_t *, const vlc_mouse_t * );
- image_handler_t *p_image;
+static bool IsFinished( filter_sys_t * );
+static void Shuffle( filter_sys_t * );
+static int PuzzleCallback( vlc_object_t *, char const *,
+ vlc_value_t, vlc_value_t, void * );
+struct filter_sys_t
+{
+ /* */
int i_cols;
int i_rows;
+ bool b_blackslot;
int *pi_order;
int i_selected;
bool b_finished;
- bool b_blackslot;
-};
-
-/*****************************************************************************
- * Control: control facility for the vout (forwards to child vout)
- *****************************************************************************/
-static int Control( vout_thread_t *p_vout, int i_query, va_list args )
-{
- return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
-}
-
-/*****************************************************************************
- * Misc stuff...
- *****************************************************************************/
-static bool finished( vout_sys_t *p_sys )
-{
- int i;
- for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
- {
- if( i != p_sys->pi_order[i] ) return false;
- }
- return true;
-}
-static bool is_valid( vout_sys_t *p_sys )
-{
- int i, j, d=0;
- if( p_sys->b_blackslot == false ) return true;
- for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
- {
- if( p_sys->pi_order[i] == p_sys->i_cols * p_sys->i_rows - 1 )
- {
- d += i / p_sys->i_cols + 1;
- continue;
- }
- for( j = i+1; j < p_sys->i_cols * p_sys->i_rows; j++ )
- {
- if( p_sys->pi_order[j] == p_sys->i_cols * p_sys->i_rows - 1 )
- continue;
- if( p_sys->pi_order[i] > p_sys->pi_order[j] ) d++;
- }
- }
- if( d%2!=0 ) return false;
- else return true;
-}
-static void shuffle( vout_sys_t *p_sys )
-{
- int i, c;
- free( p_sys->pi_order );
- p_sys->pi_order = malloc( p_sys->i_cols * p_sys->i_rows * sizeof( int ) );
- do
- {
- for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
- {
- p_sys->pi_order[i] = -1;
- }
- i = 0;
- for( c = 0; c < p_sys->i_cols * p_sys->i_rows; )
- {
- i = rand()%( p_sys->i_cols * p_sys->i_rows );
- if( p_sys->pi_order[i] == -1 )
- {
- p_sys->pi_order[i] = c;
- c++;
- }
- }
- p_sys->b_finished = finished( p_sys );
- } while( p_sys->b_finished == true
- || is_valid( p_sys ) == false );
-
- if( p_sys->b_blackslot == true )
- {
- for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
- {
- if( p_sys->pi_order[i] ==
- p_sys->i_cols * p_sys->i_rows - 1 )
- {
- p_sys->i_selected = i;
- break;
- }
- }
- }
- else
- {
- p_sys->i_selected = -1;
- }
-}
-
-/*****************************************************************************
- * Create: allocates Magnify video thread output method
- *****************************************************************************/
-static int Create( vlc_object_t *p_this )
-{
- vout_thread_t *p_vout = (vout_thread_t *)p_this;
-
- /* Allocate structure */
- p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
- if( p_vout->p_sys == NULL )
+ /* */
+ vlc_mutex_t lock;
+ bool b_change;
+ struct
{
- msg_Err( p_vout, "out of memory" );
- return VLC_ENOMEM;
- }
-
- p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
-
- config_ChainParse( p_vout, CFG_PREFIX, ppsz_filter_options,
- p_vout->p_cfg );
-
- p_vout->p_sys->i_rows =
- var_CreateGetIntegerCommand( p_vout, CFG_PREFIX "rows" );
- p_vout->p_sys->i_cols =
- var_CreateGetIntegerCommand( p_vout, CFG_PREFIX "cols" );
- p_vout->p_sys->b_blackslot =
- var_CreateGetBoolCommand( p_vout, CFG_PREFIX "black-slot" );
- var_AddCallback( p_vout, CFG_PREFIX "rows",
- PuzzleCallback, p_vout->p_sys );
- var_AddCallback( p_vout, CFG_PREFIX "cols",
- PuzzleCallback, p_vout->p_sys );
- var_AddCallback( p_vout, CFG_PREFIX "black-slot",
- PuzzleCallback, p_vout->p_sys );
-
- p_vout->p_sys->pi_order = NULL;
- shuffle( p_vout->p_sys );
-
- p_vout->pf_init = Init;
- p_vout->pf_end = End;
- p_vout->pf_manage = NULL;
- p_vout->pf_render = Render;
- p_vout->pf_display = NULL;
- p_vout->pf_control = Control;
-
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * Init: initialize Magnify video thread output method
- *****************************************************************************/
-static int Init( vout_thread_t *p_vout )
-{
- int i_index;
- picture_t *p_pic;
- video_format_t fmt;
- memset( &fmt, 0, sizeof( video_format_t ) );
-
- I_OUTPUTPICTURES = 0;
-
- /* Initialize the output structure */
- p_vout->output.i_chroma = p_vout->render.i_chroma;
- p_vout->output.i_width = p_vout->render.i_width;
- p_vout->output.i_height = p_vout->render.i_height;
- p_vout->output.i_aspect = p_vout->render.i_aspect;
-
- p_vout->fmt_out = p_vout->fmt_in;
- fmt = p_vout->fmt_out;
-
- /* Try to open the real video output */
- msg_Dbg( p_vout, "spawning the real video output" );
-
- p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
-
- /* Everything failed */
- if( p_vout->p_sys->p_vout == NULL )
- {
- msg_Err( p_vout, "cannot open vout, aborting" );
- return VLC_EGENERIC;
- }
-
- var_AddCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout );
- var_AddCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout );
- var_AddCallback( p_vout->p_sys->p_vout, "mouse-clicked",
- MouseEvent, p_vout);
-
- ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
- ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
- ADD_PARENT_CALLBACKS( SendEventsToChild );
-
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * End: terminate Magnify video thread output method
- *****************************************************************************/
-static void End( vout_thread_t *p_vout )
-{
- int i_index;
-
- /* Free the fake output buffers we allocated */
- for( i_index = I_OUTPUTPICTURES ; i_index ; )
- {
- i_index--;
- free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
- }
-
- var_DelCallback( p_vout->p_sys->p_vout, "mouse-x", MouseEvent, p_vout);
- var_DelCallback( p_vout->p_sys->p_vout, "mouse-y", MouseEvent, p_vout);
- var_DelCallback( p_vout->p_sys->p_vout, "mouse-clicked", MouseEvent, p_vout);
-}
+ int i_cols;
+ int i_rows;
+ bool b_blackslot;
+ } change;
+};
#define SHUFFLE_WIDTH 81
#define SHUFFLE_HEIGHT 13
"...... ...... .... ...... .... ....... ......... ........ ...... .......",
". .... ...... .... ...... ... ....... ......... ........ ....... .... .",
".. ....... .... ....... . ....... ......... ........ ........ ..",
-"................................................................................."};
+"................................................................................."
+};
-/*****************************************************************************
- * Destroy: destroy Magnify video thread output method
- *****************************************************************************/
-static void Destroy( vlc_object_t *p_this )
+/**
+ * Open the filter
+ */
+static int Open( vlc_object_t *p_this )
{
- vout_thread_t *p_vout = (vout_thread_t *)p_this;
+ filter_t *p_filter = (filter_t *)p_this;
+ filter_sys_t *p_sys;
- if( p_vout->p_sys->p_vout )
+ /* */
+ if( !es_format_IsSimilar( &p_filter->fmt_in, &p_filter->fmt_out ) )
{
- DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
- vlc_object_detach( p_vout->p_sys->p_vout );
- vout_Destroy( p_vout->p_sys->p_vout );
+ msg_Err( p_filter, "Input and output format does not match" );
+ return VLC_EGENERIC;
}
- image_HandlerDelete( p_vout->p_sys->p_image );
- free( p_vout->p_sys->pi_order );
+ /* Allocate structure */
+ p_filter->p_sys = p_sys = malloc( sizeof( *p_sys ) );
+ if( !p_sys )
+ return VLC_ENOMEM;
+
+ config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
+ p_filter->p_cfg );
+
+ p_sys->pi_order = NULL;
- DEL_PARENT_CALLBACKS( SendEventsToChild );
+ vlc_mutex_init( &p_sys->lock );
+ p_sys->change.i_rows =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "rows" );
+ p_sys->change.i_cols =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "cols" );
+ p_sys->change.b_blackslot =
+ var_CreateGetBoolCommand( p_filter, CFG_PREFIX "black-slot" );
+ p_sys->b_change = true;
- free( p_vout->p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "rows", PuzzleCallback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "cols", PuzzleCallback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "black-slot", PuzzleCallback, p_sys );
+
+ p_filter->pf_video_filter = Filter;
+ p_filter->pf_video_mouse = Mouse;
+
+ return VLC_SUCCESS;
}
-/*****************************************************************************
- * Render: displays previously rendered output
- *****************************************************************************/
-static void Render( vout_thread_t *p_vout, picture_t *p_pic )
+/**
+ * Close the filter
+ */
+static void Close( vlc_object_t *p_this )
{
- picture_t *p_outpic;
+ filter_t *p_filter = (filter_t *)p_this;
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ var_DelCallback( p_filter, CFG_PREFIX "rows", PuzzleCallback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "cols", PuzzleCallback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "black-slot", PuzzleCallback, p_sys );
+
+ vlc_mutex_destroy( &p_sys->lock );
+ free( p_sys->pi_order );
- //video_format_t fmt_out;
- // memset( &fmt_out, 0, sizeof(video_format_t) );
- //picture_t *p_converted;
+ free( p_sys );
+}
- int i_plane;
+/**
+ * Filter a picture
+ */
+static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
- int i_rows = p_vout->p_sys->i_rows;
- int i_cols = p_vout->p_sys->i_cols;
+ picture_t *p_outpic = filter_NewPicture( p_filter );
+ if( !p_outpic )
+ {
+ picture_Release( p_pic );
+ return NULL;
+ }
- /* This is a new frame. Get a structure from the video_output. */
- while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
- == NULL )
+ /* */
+ vlc_mutex_lock( &p_sys->lock );
+ if( p_sys->b_change )
{
- if( p_vout->b_die || p_vout->b_error )
- {
- return;
- }
- msleep( VOUT_OUTMEM_SLEEP );
+ p_sys->i_rows = p_sys->change.i_rows;
+ p_sys->i_cols = p_sys->change.i_cols;
+ p_sys->b_blackslot = p_sys->change.b_blackslot;
+ p_sys->b_change = false;
+
+ Shuffle( p_sys );
}
+ vlc_mutex_unlock( &p_sys->lock );
- vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
+ /* */
+ const int i_rows = p_sys->i_rows;
+ const int i_cols = p_sys->i_cols;
- for( i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
+ /* Draw each piece of the puzzle at the right place */
+ for( int i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
{
- plane_t *p_in = p_pic->p+i_plane;
- plane_t *p_out = p_outpic->p+i_plane;
- int i_pitch = p_in->i_pitch;
- int i;
+ const plane_t *p_in = &p_pic->p[i_plane];
+ plane_t *p_out = &p_outpic->p[i_plane];
- for( i = 0; i < i_cols * i_rows; i++ )
+ for( int i = 0; i < i_cols * i_rows; i++ )
{
- int i_col = i % i_cols;
- int i_row = i / i_cols;
- int i_ocol = p_vout->p_sys->pi_order[i] % i_cols;
- int i_orow = p_vout->p_sys->pi_order[i] / i_cols;
- int i_last_row = i_row + 1;
- i_orow *= p_in->i_lines / i_rows;
- i_row *= p_in->i_lines / i_rows;
- i_last_row *= p_in->i_lines / i_rows;
-
- if( p_vout->p_sys->b_blackslot == true
- && p_vout->p_sys->b_finished == false
- && i == p_vout->p_sys->i_selected )
+ int i_piece_height = p_out->i_visible_lines / i_rows;
+ int i_piece_width = p_out->i_visible_pitch / i_cols;
+
+ int i_col = (i % i_cols) * i_piece_width;
+ int i_row = (i / i_cols) * i_piece_height;
+ int i_last_row = i_row + i_piece_height;
+
+ int i_ocol = (p_sys->pi_order[i] % i_cols) * i_piece_width;
+ int i_orow = (p_sys->pi_order[i] / i_cols) * i_piece_height;
+
+ if( p_sys->b_blackslot && !p_sys->b_finished && i == p_sys->i_selected )
{
uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
- for( ; i_row < i_last_row; i_row++, i_orow++ )
+ for( int r = i_row; r < i_last_row; r++ )
{
- vlc_memset( p_out->p_pixels + i_row * i_pitch
- + i_col * i_pitch / i_cols,
- color, i_pitch / i_cols );
+ memset( p_out->p_pixels + r * p_out->i_pitch + i_col,
+ color, i_piece_width );
}
}
else
{
- for( ; i_row < i_last_row; i_row++, i_orow++ )
+ for( int r = i_row, or = i_orow; r < i_last_row; r++, or++ )
{
- vlc_memcpy( p_out->p_pixels + i_row * i_pitch
- + i_col * i_pitch / i_cols,
- p_in->p_pixels + i_orow * i_pitch
- + i_ocol * i_pitch / i_cols,
- i_pitch / i_cols );
+ memcpy( p_out->p_pixels + r * p_out->i_pitch + i_col,
+ p_in->p_pixels + or * p_in->i_pitch + i_ocol,
+ i_piece_width );
}
}
- }
- }
- if( p_vout->p_sys->i_selected != -1
- && p_vout->p_sys->b_blackslot == false )
- {
- plane_t *p_in = p_pic->p+Y_PLANE;
- plane_t *p_out = p_outpic->p+Y_PLANE;
- int i_pitch = p_in->i_pitch;
- int i_col = p_vout->p_sys->i_selected % i_cols;
- int i_row = p_vout->p_sys->i_selected / i_cols;
- int i_last_row = i_row + 1;
- i_row *= p_in->i_lines / i_rows;
- i_last_row *= p_in->i_lines / i_rows;
- vlc_memset( p_out->p_pixels + i_row * i_pitch
- + i_col * i_pitch / i_cols,
- 0xff, i_pitch / i_cols );
- for( ; i_row < i_last_row; i_row++ )
- {
- p_out->p_pixels[ i_row * i_pitch
- + i_col * i_pitch / i_cols ] = 0xff;
- p_out->p_pixels[ i_row * i_pitch
- + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
+ /* Draw the borders of the selected slot */
+ if( i_plane == 0 && !p_sys->b_blackslot && p_sys->i_selected == i )
+ {
+ memset( p_out->p_pixels + i_row * p_out->i_pitch + i_col,
+ 0xff, i_piece_width );
+ for( int r = i_row; r < i_last_row; r++ )
+ {
+ p_out->p_pixels[r * p_out->i_pitch + i_col + 0 + 0 ] = 0xff;
+ p_out->p_pixels[r * p_out->i_pitch + i_col + i_piece_width - 1 ] = 0xff;
+ }
+ memset( p_out->p_pixels + (i_last_row - 1) * p_out->i_pitch + i_col,
+ 0xff, i_piece_width );
+ }
}
- i_row--;
- vlc_memset( p_out->p_pixels + i_row * i_pitch
- + i_col * i_pitch / i_cols,
- 0xff, i_pitch / i_cols );
}
- if( p_vout->p_sys->b_finished == true )
+ /* Draw the 'Shuffle' button if the puzzle is finished */
+ if( p_sys->b_finished )
{
- int i, j;
- plane_t *p_out = p_outpic->p+Y_PLANE;
- int i_pitch = p_out->i_pitch;
- for( i = 0; i < SHUFFLE_HEIGHT; i++ )
+ plane_t *p_out = &p_outpic->p[Y_PLANE];
+ for( int i = 0; i < SHUFFLE_HEIGHT; i++ )
{
- for( j = 0; j < SHUFFLE_WIDTH; j++ )
+ for( int j = 0; j < SHUFFLE_WIDTH; j++ )
{
if( shuffle_button[i][j] == '.' )
- p_out->p_pixels[ i * i_pitch + j ] = 0xff;
+ p_out->p_pixels[ i * p_out->i_pitch + j ] = 0xff;
}
}
}
- vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
+ return CopyInfoAndRelease( p_outpic, p_pic );
}
-/*****************************************************************************
- * SendEvents: forward mouse and keyboard events to the parent p_vout
- *****************************************************************************/
-static int SendEvents( vlc_object_t *p_this, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
+static int Mouse( filter_t *p_filter, vlc_mouse_t *p_mouse,
+ const vlc_mouse_t *p_old, const vlc_mouse_t *p_new )
{
- VLC_UNUSED(p_this); VLC_UNUSED(oldval);
+ filter_sys_t *p_sys = p_filter->p_sys;
+ const video_format_t *p_fmt = &p_filter->fmt_in.video;
- var_Set( (vlc_object_t *)p_data, psz_var, newval );
+ /* Only take events inside the puzzle erea */
+ if( p_new->i_x < 0 || p_new->i_x >= (int)p_fmt->i_width ||
+ p_new->i_y < 0 || p_new->i_y >= (int)p_fmt->i_height )
+ return VLC_EGENERIC;
- return VLC_SUCCESS;
-}
+ /* */
+ const bool b_clicked = vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT );
-/*****************************************************************************
- * SendEventsToChild: forward events to the child/children vout
- *****************************************************************************/
-static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- VLC_UNUSED(p_data); VLC_UNUSED(oldval);
- vout_thread_t *p_vout = (vout_thread_t *)p_this;
- var_Set( p_vout->p_sys->p_vout, psz_var, newval );
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * MouseEvent: callback for mouse events
- *****************************************************************************/
-static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(newval);
- vout_thread_t *p_vout = (vout_thread_t*)p_data;
- int i_x, i_y;
- int i_v;
-
-#define MOUSE_DOWN 1
-#define MOUSE_CLICKED 2
-#define MOUSE_MOVE_X 4
-#define MOUSE_MOVE_Y 8
-#define MOUSE_MOVE 12
- uint8_t mouse= 0;
-
- int v_h = p_vout->output.i_height;
- int v_w = p_vout->output.i_width;
- int i_pos;
-
- if( psz_var[6] == 'x' ) mouse |= MOUSE_MOVE_X;
- if( psz_var[6] == 'y' ) mouse |= MOUSE_MOVE_Y;
- if( psz_var[6] == 'c' ) mouse |= MOUSE_CLICKED;
-
- i_v = var_GetInteger( p_vout->p_sys->p_vout, "mouse-button-down" );
- if( i_v & 0x1 ) mouse |= MOUSE_DOWN;
- i_y = var_GetInteger( p_vout->p_sys->p_vout, "mouse-y" );
- i_x = var_GetInteger( p_vout->p_sys->p_vout, "mouse-x" );
-
- if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
- return VLC_SUCCESS;
-
- if( mouse & MOUSE_CLICKED )
+ /* If the puzzle is finished, shuffle it if needed */
+ if( p_sys->b_finished )
{
- 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;
- if( p_vout->p_sys->b_finished == true
- && i_x < SHUFFLE_WIDTH && i_y < SHUFFLE_HEIGHT )
+ if( b_clicked &&
+ p_new->i_x < SHUFFLE_WIDTH && p_new->i_y < SHUFFLE_HEIGHT )
{
- shuffle( p_vout->p_sys );
+ p_sys->b_change = true;
+ return VLC_EGENERIC;
}
- else if( p_vout->p_sys->i_selected == -1 )
+ else
{
- p_vout->p_sys->i_selected = i_pos;
+ /* This is the only case where we can forward the mouse */
+ *p_mouse = *p_new;
+ return VLC_SUCCESS;
}
- else if( p_vout->p_sys->i_selected == i_pos
- && p_vout->p_sys->b_blackslot == false )
- {
- p_vout->p_sys->i_selected = -1;
- }
- else if( ( p_vout->p_sys->i_selected == i_pos + 1
- && p_vout->p_sys->i_selected%p_vout->p_sys->i_cols != 0 )
- || ( p_vout->p_sys->i_selected == i_pos - 1
- && i_pos % p_vout->p_sys->i_cols != 0 )
- || p_vout->p_sys->i_selected == i_pos + p_vout->p_sys->i_cols
- || p_vout->p_sys->i_selected == i_pos - p_vout->p_sys->i_cols )
- {
- int a = p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ];
- p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ] =
- p_vout->p_sys->pi_order[ i_pos ];
- p_vout->p_sys->pi_order[ i_pos ] = a;
- if( p_vout->p_sys->b_blackslot == true )
- p_vout->p_sys->i_selected = i_pos;
- else
- p_vout->p_sys->i_selected = -1;
+ }
+ if( !b_clicked )
+ return VLC_EGENERIC;
- p_vout->p_sys->b_finished = finished( p_vout->p_sys );
- }
+ /* */
+ const int i_pos_x = p_new->i_x * p_sys->i_cols / p_fmt->i_width;
+ const int i_pos_y = p_new->i_y * p_sys->i_rows / p_fmt->i_height;
+ const int i_pos = i_pos_y * p_sys->i_cols + i_pos_x;
+
+ if( p_sys->i_selected == -1 )
+ {
+ p_sys->i_selected = i_pos;
}
- return VLC_SUCCESS;
+ else if( p_sys->i_selected == i_pos && !p_sys->b_blackslot )
+ {
+ p_sys->i_selected = -1;
+ }
+ else if( ( p_sys->i_selected == i_pos + 1 && p_sys->i_selected%p_sys->i_cols != 0 )
+ || ( p_sys->i_selected == i_pos - 1 && i_pos % p_sys->i_cols != 0 )
+ || p_sys->i_selected == i_pos + p_sys->i_cols
+ || p_sys->i_selected == i_pos - p_sys->i_cols )
+ {
+ /* Swap two pieces */
+ int a = p_sys->pi_order[ p_sys->i_selected ];
+ p_sys->pi_order[ p_sys->i_selected ] = p_sys->pi_order[ i_pos ];
+ p_sys->pi_order[ i_pos ] = a;
+
+ p_sys->i_selected = p_sys->b_blackslot ? i_pos : -1;
+ p_sys->b_finished = IsFinished( p_sys );
+ }
+ return VLC_EGENERIC;
}
+/*****************************************************************************
+ * Misc stuff...
+ *****************************************************************************/
static int PuzzleCallback( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval,
void *p_data )
{
VLC_UNUSED(p_this); VLC_UNUSED(oldval);
- vout_sys_t *p_sys = (vout_sys_t *)p_data;
+ filter_sys_t *p_sys = (filter_sys_t *)p_data;
+
+ vlc_mutex_lock( &p_sys->lock );
if( !strcmp( psz_var, CFG_PREFIX "rows" ) )
{
- p_sys->i_rows = __MAX( 1, newval.i_int );
+ p_sys->change.i_rows = __MAX( 1, newval.i_int );
}
else if( !strcmp( psz_var, CFG_PREFIX "cols" ) )
{
- p_sys->i_cols = __MAX( 1, newval.i_int );
+ p_sys->change.i_cols = __MAX( 1, newval.i_int );
}
else if( !strcmp( psz_var, CFG_PREFIX "black-slot" ) )
{
- p_sys->b_blackslot = newval.b_bool;
+ p_sys->change.b_blackslot = newval.b_bool;
}
- shuffle( p_sys );
+ p_sys->b_change = true;
+ vlc_mutex_unlock( &p_sys->lock );
+
return VLC_SUCCESS;
}
+
+static bool IsFinished( filter_sys_t *p_sys )
+{
+ for( int i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
+ {
+ if( i != p_sys->pi_order[i] )
+ return false;
+ }
+ return true;
+}
+
+static bool IsValid( filter_sys_t *p_sys )
+{
+ const int i_count = p_sys->i_cols * p_sys->i_rows;
+
+ if( !p_sys->b_blackslot )
+ return true;
+
+ int d = 0;
+ for( int i = 0; i < i_count; i++ )
+ {
+ if( p_sys->pi_order[i] == i_count - 1 )
+ {
+ d += i / p_sys->i_cols + 1;
+ continue;
+ }
+ for( int j = i+1; j < i_count; j++ )
+ {
+ if( p_sys->pi_order[j] == i_count - 1 )
+ continue;
+ if( p_sys->pi_order[i] > p_sys->pi_order[j] )
+ d++;
+ }
+ }
+ return (d%2) == 0;
+}
+
+static void Shuffle( filter_sys_t *p_sys )
+{
+ const unsigned i_count = p_sys->i_cols * p_sys->i_rows;
+
+ free( p_sys->pi_order );
+
+ p_sys->pi_order = calloc( i_count, sizeof(*p_sys->pi_order) );
+ do
+ {
+ for( unsigned i = 0; i < i_count; i++ )
+ p_sys->pi_order[i] = -1;
+
+ for( unsigned c = 0; c < i_count; )
+ {
+ unsigned i = ((unsigned)vlc_mrand48()) % i_count;
+ if( p_sys->pi_order[i] == -1 )
+ p_sys->pi_order[i] = c++;
+ }
+ p_sys->b_finished = IsFinished( p_sys );
+
+ } while( p_sys->b_finished || !IsValid( p_sys ) );
+
+ if( p_sys->b_blackslot )
+ {
+ for( unsigned i = 0; i < i_count; i++ )
+ {
+ if( p_sys->pi_order[i] == i_count - 1 )
+ {
+ p_sys->i_selected = i;
+ break;
+ }
+ }
+ }
+ else
+ {
+ p_sys->i_selected = -1;
+ }
+}
+