/*****************************************************************************
* puzzle.c : Puzzle game
*****************************************************************************
- * Copyright (C) 2005-2006 the VideoLAN team
+ * Copyright (C) 2005-2009 VLC authors and VideoLAN
+ * Copyright (C) 2013 Vianney Boyer
* $Id$
*
* Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
+ * Vianney Boyer <vlcvboyer -at- gmail -dot- com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
-#include <vlc/vlc.h>
-#include <vlc_vout.h>
-
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
#include <math.h>
-#include "filter_common.h"
-#include "vlc_image.h"
-#include "vlc_input.h"
-#include "vlc_playlist.h"
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_filter.h>
+#include <vlc_rand.h>
-/*****************************************************************************
- * Local prototypes
- *****************************************************************************/
-static int Create ( vlc_object_t * );
-static void Destroy ( vlc_object_t * );
+#include "filter_picture.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 "puzzle.h"
+#include "puzzle_bezier.h"
+#include "puzzle_lib.h"
+#include "puzzle_pce.h"
+#include "puzzle_mgt.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 COLS_LONGTEXT N_("Number of puzzle columns")
-#define BLACKSLOT_TEXT N_("Make one tile a black slot")
-#define BLACKSLOT_LONGTEXT N_("Make one slot black. Other tiles can only be swapped with the black slot.")
+#define MODE_TEXT N_("Game mode")
+#define MODE_LONGTEXT N_("Select game mode variation from jigsaw puzzle to sliding puzzle.")
+#define BORDER_TEXT N_("Border")
+#define BORDER_LONGTEXT N_("Unshuffled Border width.")
+#define PREVIEW_TEXT N_("Small preview")
+#define PREVIEW_LONGTEXT N_("Show small preview.")
+#define PREVIEWSIZE_TEXT N_("Small preview size")
+#define PREVIEWSIZE_LONGTEXT N_("Show small preview size (percent of source).")
+#define SHAPE_SIZE_TEXT N_("Piece edge shape size")
+#define SHAPE_SIZE_LONGTEXT N_("Size of the curve along the piece's edge")
+#define AUTO_SHUFFLE_TEXT N_("Auto shuffle")
+#define AUTO_SHUFFLE_LONGTEXT N_("Auto shuffle delay during game")
+#define AUTO_SOLVE_TEXT N_("Auto solve")
+#define AUTO_SOLVE_LONGTEXT N_("Auto solve delay during game")
+#define ROTATION_TEXT N_("Rotation")
+#define ROTATION_LONGTEXT N_("Rotation parameter: none;180;90-270;mirror")
+
+const int pi_mode_values[] = { (int) 0, (int) 1, (int) 2, (int) 3 };
+const char *const ppsz_mode_descriptions[] = { N_("jigsaw puzzle"), N_("sliding puzzle"), N_("swap puzzle"), N_("exchange puzzle") };
+const int pi_rotation_values[] = { (int) 0, (int) 1, (int) 2, (int) 3 };
+const char *const ppsz_rotation_descriptions[] = { N_("0"), N_("0/180"), N_("0/90/180/270"), N_("0/90/180/270/mirror") };
#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 );
-
- add_integer_with_range( CFG_PREFIX "rows", 4, 1, 128, NULL,
- ROWS_TEXT, ROWS_LONGTEXT, VLC_FALSE );
- change_safe();
- add_integer_with_range( CFG_PREFIX "cols", 4, 1, 128, NULL,
- COLS_TEXT, COLS_LONGTEXT, VLC_FALSE );
- change_safe();
- add_bool( CFG_PREFIX "black-slot", 0, NULL,
- BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, VLC_FALSE );
- change_safe();
-
- set_callbacks( Create, Destroy );
-vlc_module_end();
-
-static const char *ppsz_filter_options[] = {
- "rows", "cols", "black-slot", NULL
-};
+int Open ( vlc_object_t * );
+void Close( vlc_object_t * );
+
+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 )
+
+ add_integer_with_range( CFG_PREFIX "rows", 4, 2, 16,
+ ROWS_TEXT, ROWS_LONGTEXT, false )
+ add_integer_with_range( CFG_PREFIX "cols", 4, 2, 16,
+ COLS_TEXT, COLS_LONGTEXT, false )
+ add_integer_with_range( CFG_PREFIX "border", 3, 0, 40,
+ BORDER_TEXT, BORDER_LONGTEXT, false )
+ add_bool( CFG_PREFIX "preview", false,
+ PREVIEW_TEXT, PREVIEW_LONGTEXT, false )
+ add_integer_with_range( CFG_PREFIX "preview-size", 15, 0, 100,
+ PREVIEWSIZE_TEXT, PREVIEWSIZE_LONGTEXT, false )
+ add_integer_with_range( CFG_PREFIX "shape-size", 90, 0, 100,
+ SHAPE_SIZE_TEXT, SHAPE_SIZE_LONGTEXT, false )
+ add_integer_with_range( CFG_PREFIX "auto-shuffle", 0, 0, 30000,
+ AUTO_SHUFFLE_TEXT, AUTO_SHUFFLE_LONGTEXT, false )
+ add_integer_with_range( CFG_PREFIX "auto-solve", 0, 0, 30000,
+ AUTO_SOLVE_TEXT, AUTO_SOLVE_LONGTEXT, false )
+ add_integer( CFG_PREFIX "rotation", 0,
+ ROTATION_TEXT, ROTATION_LONGTEXT, false )
+ change_integer_list(pi_rotation_values, ppsz_rotation_descriptions )
+ add_integer( CFG_PREFIX "mode", 0,
+ MODE_TEXT, MODE_LONGTEXT, false )
+ change_integer_list(pi_mode_values, ppsz_mode_descriptions )
+
+ set_callbacks( Open, Close )
+vlc_module_end()
/*****************************************************************************
- * vout_sys_t: Magnify video output method descriptor
+ * Local prototypes
*****************************************************************************/
-struct vout_sys_t
+
+const char *const ppsz_filter_options[] = {
+ "rows", "cols","border", "preview", "preview-size", "mode", "shape-size", "auto-shuffle", "auto-solve", "rotation", NULL
+};
+
+/**
+ * Open the filter
+ */
+int Open( vlc_object_t *p_this )
{
- vout_thread_t *p_vout;
+ filter_t *p_filter = (filter_t *)p_this;
+ filter_sys_t *p_sys;
- image_handler_t *p_image;
+ /* Assert video in match with video out */
+ if( !es_format_IsSimilar( &p_filter->fmt_in, &p_filter->fmt_out ) ) {
+ msg_Err( p_filter, "Input and output format does not match" );
+ return VLC_EGENERIC;
+ }
- int i_cols;
- int i_rows;
- int *pi_order;
- int i_selected;
- vlc_bool_t b_finished;
+ const vlc_chroma_description_t *p_chroma =
+ vlc_fourcc_GetChromaDescription( p_filter->fmt_in.video.i_chroma );
+ if( p_chroma == NULL || p_chroma->plane_count == 0 )
+ return VLC_EGENERIC;
- vlc_bool_t b_blackslot;
-};
+ /* Allocate structure */
+ p_filter->p_sys = p_sys = calloc(1, sizeof( *p_sys ) );
+ if( !p_sys )
+ return VLC_ENOMEM;
-/*****************************************************************************
- * 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 );
-}
+ /* init some values */
+ p_sys->b_shuffle_rqst = true;
+ p_sys->b_change_param = true;
+ p_sys->i_mouse_drag_pce = NO_PCE;
+ p_sys->i_pointed_pce = NO_PCE;
+ p_sys->i_magnet_accuracy = 3;
-/*****************************************************************************
- * Misc stuff...
- *****************************************************************************/
-static vlc_bool_t finished( vout_sys_t *p_sys )
-{
- int i;
- for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
+ /* Generate values of random bezier shapes */
+ p_sys->ps_bezier_pts_H = calloc( SHAPES_QTY, sizeof( point_t *) );
+ if( !p_sys->ps_bezier_pts_H )
{
- if( i != p_sys->pi_order[i] ) return VLC_FALSE;
+ free(p_filter->p_sys);
+ p_filter->p_sys = NULL;
+ return VLC_ENOMEM;
}
- return VLC_TRUE;
+ for (int32_t i_shape = 0; i_shape<SHAPES_QTY; i_shape++)
+ p_sys->ps_bezier_pts_H[i_shape] = puzzle_rand_bezier(7);
+
+
+ config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
+ p_filter->p_cfg );
+
+ vlc_mutex_init( &p_sys->lock );
+ vlc_mutex_init( &p_sys->pce_lock );
+
+ p_sys->s_new_param.i_rows =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "rows" );
+ p_sys->s_new_param.i_cols =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "cols" );
+ p_sys->s_new_param.i_border =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "border" );
+ p_sys->s_new_param.b_preview =
+ var_CreateGetBoolCommand( p_filter, CFG_PREFIX "preview" );
+ p_sys->s_new_param.i_preview_size =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "preview-size" );
+ p_sys->s_new_param.i_shape_size =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "shape-size" );
+ p_sys->s_new_param.i_auto_shuffle_speed =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "auto-shuffle" );
+ p_sys->s_new_param.i_auto_solve_speed =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "auto-solve" );
+ p_sys->s_new_param.i_rotate =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "rotation" );
+ p_sys->s_new_param.i_mode =
+ var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "mode" );
+
+ var_AddCallback( p_filter, CFG_PREFIX "rows", puzzle_Callback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "cols", puzzle_Callback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "border", puzzle_Callback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "preview", puzzle_Callback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "preview-size", puzzle_Callback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "shape-size", puzzle_Callback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "auto-shuffle", puzzle_Callback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "auto-solve", puzzle_Callback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "rotation", puzzle_Callback, p_sys );
+ var_AddCallback( p_filter, CFG_PREFIX "mode", puzzle_Callback, p_sys );
+
+ p_filter->pf_video_filter = Filter;
+ p_filter->pf_video_mouse = puzzle_mouse;
+
+ return VLC_SUCCESS;
}
-static vlc_bool_t is_valid( vout_sys_t *p_sys )
-{
- int i, j, d=0;
- if( p_sys->b_blackslot == VLC_FALSE ) return VLC_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 )
+
+/**
+ * Close the filter
+ */
+void Close( vlc_object_t *p_this ) {
+ filter_t *p_filter = (filter_t *)p_this;
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ var_DelCallback( p_filter, CFG_PREFIX "rows", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "cols", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "border", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "preview", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "preview-size", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "shape-size", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "auto-shuffle", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "auto-solve", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "rotation", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "mode", puzzle_Callback, p_sys );
+
+ vlc_mutex_destroy( &p_sys->lock );
+ vlc_mutex_destroy( &p_sys->pce_lock );
+
+ /* Free allocated memory */
+ puzzle_free_ps_puzzle_array ( p_filter );
+ puzzle_free_ps_pieces_shapes ( p_filter);
+ puzzle_free_ps_pieces ( p_filter );
+ free(p_sys->ps_desk_planes);
+ free(p_sys->ps_pict_planes);
+ free( p_sys->pi_order );
+
+ for (int32_t i_shape = 0; i_shape<SHAPES_QTY; i_shape++)
+ free(p_sys->ps_bezier_pts_H[i_shape]);
+ free(p_sys->ps_bezier_pts_H);
+
+ free( p_sys );
+}
+
+/**
+ * Filter a picture
+ */
+picture_t *Filter( filter_t *p_filter, picture_t *p_pic_in ) {
+ if( !p_pic_in || !p_filter) return NULL;
+
+ const video_format_t *p_fmt_in = &p_filter->fmt_in.video;
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ picture_t *p_pic_out = filter_NewPicture( p_filter );
+ if( !p_pic_out ) {
+ picture_Release( p_pic_in );
+ return NULL;
+ }
+
+ int i_ret = 0;
+ p_sys->b_bake_request = false;
+
+ if ((p_sys->pi_order == NULL) || (p_sys->ps_desk_planes == NULL) || (p_sys->ps_pict_planes == NULL) || (p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL))
+ p_sys->b_init = false;
+
+ if ((p_sys->ps_pieces_shapes == NULL) && p_sys->s_current_param.b_advanced && (p_sys->s_current_param.i_shape_size != 0))
+ p_sys->b_init = false;
+
+ /* assert initialized & allocated data match with current frame characteristics */
+ if ( p_sys->s_allocated.i_planes != p_pic_out->i_planes)
+ p_sys->b_init = false;
+ p_sys->s_current_param.i_planes = p_pic_out->i_planes;
+ if (p_sys->ps_pict_planes != NULL) {
+ for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) {
+ if ( (p_sys->ps_pict_planes[i_plane].i_lines != p_pic_in->p[i_plane].i_visible_lines)
+ || (p_sys->ps_pict_planes[i_plane].i_width != p_pic_in->p[i_plane].i_visible_pitch / p_pic_in->p[i_plane].i_pixel_pitch)
+ || (p_sys->ps_desk_planes[i_plane].i_lines != p_pic_out->p[i_plane].i_visible_lines)
+ || (p_sys->ps_desk_planes[i_plane].i_width != p_pic_out->p[i_plane].i_visible_pitch / p_pic_out->p[i_plane].i_pixel_pitch) )
+ p_sys->b_init = false;
+ }
+ }
+
+ p_sys->s_current_param.i_pict_width = (int) p_pic_in->p[0].i_visible_pitch / p_pic_in->p[0].i_pixel_pitch;
+ p_sys->s_current_param.i_pict_height = (int) p_pic_in->p[0].i_visible_lines;
+ p_sys->s_current_param.i_desk_width = (int) p_pic_out->p[0].i_visible_pitch / p_pic_out->p[0].i_pixel_pitch;
+ p_sys->s_current_param.i_desk_height = (int) p_pic_out->p[0].i_visible_lines;
+
+ /* assert no mismatch between sizes */
+ if ( p_sys->s_current_param.i_pict_width != p_sys->s_current_param.i_desk_width
+ || p_sys->s_current_param.i_pict_height != p_sys->s_current_param.i_desk_height
+ || p_sys->s_current_param.i_pict_width != (int) p_fmt_in->i_width
+ || p_sys->s_current_param.i_pict_height != (int) p_fmt_in->i_height )
+ return NULL;
+
+ vlc_mutex_lock( &p_sys->lock );
+
+ /* check if we have to compute initial data */
+ if ( p_sys->b_change_param || p_sys->b_bake_request || !p_sys->b_init ) {
+ if ( p_sys->s_allocated.i_rows != p_sys->s_new_param.i_rows
+ || p_sys->s_allocated.i_cols != p_sys->s_new_param.i_cols
+ || p_sys->s_allocated.i_rotate != p_sys->s_new_param.i_rotate
+ || p_sys->s_allocated.i_mode != p_sys->s_new_param.i_mode
+ || p_sys->b_bake_request || !p_sys->b_init )
{
- d += i / p_sys->i_cols + 1;
- continue;
+ p_sys->b_bake_request = true;
+ p_sys->b_init = false;
+ p_sys->b_shuffle_rqst = true;
+ p_sys->b_shape_init = false;
}
- for( j = i+1; j < p_sys->i_cols * p_sys->i_rows; j++ )
+
+ if ( p_sys->s_current_param.i_border != p_sys->s_new_param.i_border
+ || p_sys->s_current_param.i_shape_size != p_sys->s_new_param.i_shape_size )
{
- 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++;
+ p_sys->b_bake_request = true;
+ p_sys->b_shape_init = false;
}
- }
- if( d%2!=0 ) return VLC_FALSE;
- else return VLC_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++ )
+
+ /* depending on the game selected, set associated internal flags */
+ switch ( p_sys->s_new_param.i_mode )
{
- p_sys->pi_order[i] = -1;
+ case 0: /* jigsaw puzzle */
+ p_sys->s_new_param.b_advanced = true;
+ p_sys->s_new_param.b_blackslot = false;
+ p_sys->s_new_param.b_near = false;
+ break;
+ case 1: /* sliding puzzle */
+ p_sys->s_new_param.b_advanced = false;
+ p_sys->s_new_param.b_blackslot = true;
+ p_sys->s_new_param.b_near = true;
+ break;
+ case 2: /* swap puzzle */
+ p_sys->s_new_param.b_advanced = false;
+ p_sys->s_new_param.b_blackslot = false;
+ p_sys->s_new_param.b_near = true;
+ break;
+ case 3: /* exchange puzzle */
+ p_sys->s_new_param.b_advanced = false;
+ p_sys->s_new_param.b_blackslot = false;
+ p_sys->s_new_param.b_near = false;
+ break;
+ }
+ p_sys->s_current_param.i_mode = p_sys->s_new_param.i_mode;
+
+ if ( p_sys->s_current_param.b_blackslot != p_sys->s_new_param.b_blackslot
+ && p_sys->i_selected == NO_PCE
+ && p_sys->s_current_param.b_blackslot )
+ p_sys->i_selected = 0;
+
+ if ( p_sys->s_current_param.i_auto_shuffle_speed != p_sys->s_new_param.i_auto_shuffle_speed )
+ p_sys->i_auto_shuffle_countdown_val = init_countdown(p_sys->s_new_param.i_auto_shuffle_speed);
+
+ if ( p_sys->s_current_param.i_auto_solve_speed != p_sys->s_new_param.i_auto_solve_speed )
+ p_sys->i_auto_solve_countdown_val = init_countdown(p_sys->s_current_param.i_auto_solve_speed);
+
+ p_sys->s_current_param.i_rows = p_sys->s_new_param.i_rows;
+ p_sys->s_current_param.i_cols = p_sys->s_new_param.i_cols;
+ p_sys->s_current_param.i_pieces_nbr = p_sys->s_current_param.i_rows * p_sys->s_current_param.i_cols;
+ p_sys->s_current_param.b_advanced = p_sys->s_new_param.b_advanced;
+ if (!p_sys->s_new_param.b_advanced) {
+ p_sys->s_current_param.b_blackslot = p_sys->s_new_param.b_blackslot;
+ p_sys->s_current_param.b_near = p_sys->s_new_param.b_near || p_sys->s_new_param.b_blackslot;
+ p_sys->s_current_param.i_border = 0;
+ p_sys->s_current_param.b_preview = false;
+ p_sys->s_current_param.i_preview_size= 0;
+ p_sys->s_current_param.i_shape_size = 0;
+ p_sys->s_current_param.i_auto_shuffle_speed = 0;
+ p_sys->s_current_param.i_auto_solve_speed = 0;
+ p_sys->s_current_param.i_rotate = 0;
}
- i = 0;
- for( c = 0; c < p_sys->i_cols * p_sys->i_rows; )
+ else
{
- 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->s_current_param.b_blackslot = false;
+ p_sys->s_current_param.b_near = false;
+ p_sys->s_current_param.i_border = p_sys->s_new_param.i_border;
+ p_sys->s_current_param.b_preview = p_sys->s_new_param.b_preview;
+ p_sys->s_current_param.i_preview_size = p_sys->s_new_param.i_preview_size;
+ p_sys->s_current_param.i_shape_size = p_sys->s_new_param.i_shape_size;
+ p_sys->s_current_param.i_auto_shuffle_speed = p_sys->s_new_param.i_auto_shuffle_speed;
+ p_sys->s_current_param.i_auto_solve_speed = p_sys->s_new_param.i_auto_solve_speed;
+ p_sys->s_current_param.i_rotate = p_sys->s_new_param.i_rotate;
}
- p_sys->b_finished = finished( p_sys );
- } while( p_sys->b_finished == VLC_TRUE
- || is_valid( p_sys ) == VLC_FALSE );
+ p_sys->b_change_param = false;
+ }
- if( p_sys->b_blackslot == VLC_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 )
+ vlc_mutex_unlock( &p_sys->lock );
+
+ /* generate initial puzzle data when needed */
+ if ( p_sys->b_bake_request ) {
+ if (!p_sys->b_shuffle_rqst) {
+ /* here we have to keep the same position
+ * we have to save locations before generating new data
+ */
+ save_game_t *ps_save_game = puzzle_save(p_filter);
+ if (!ps_save_game)
+ return CopyInfoAndRelease( p_pic_out, p_pic_in );
+ i_ret = puzzle_bake( p_filter, p_pic_out, p_pic_in );
+ if ( i_ret != VLC_SUCCESS )
{
- p_sys->i_selected = i;
- break;
+ free(ps_save_game->ps_pieces);
+ free(ps_save_game);
+ return CopyInfoAndRelease( p_pic_out, p_pic_in );
}
+ puzzle_load( p_filter, ps_save_game);
+ free(ps_save_game->ps_pieces);
+ free(ps_save_game);
+ }
+ else {
+ i_ret = puzzle_bake( p_filter, p_pic_out, p_pic_in );
+ if ( i_ret != VLC_SUCCESS )
+ return CopyInfoAndRelease( p_pic_out, p_pic_in );
}
}
- else
- {
- p_sys->i_selected = -1;
+
+ /* shuffle the desk and generate pieces data */
+ if ( p_sys->b_shuffle_rqst && p_sys->b_init ) {
+ i_ret = puzzle_bake_piece ( p_filter );
+ if (i_ret != VLC_SUCCESS)
+ return CopyInfoAndRelease( p_pic_out, p_pic_in );
}
-}
-/*****************************************************************************
- * 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;
+ /* preset output pic */
+ if ( !p_sys->b_bake_request && !p_sys->b_shuffle_rqst && p_sys->b_init && !p_sys->b_finished )
+ puzzle_preset_desk_background(p_pic_out, 0, 127, 127);
+ else {
+ /* copy src to dst during init & bake process */
+ for( uint8_t i_plane = 0; i_plane < p_pic_out->i_planes; i_plane++ )
+ memcpy( p_pic_out->p[i_plane].p_pixels, p_pic_in->p[i_plane].p_pixels,
+ p_pic_in->p[i_plane].i_pitch * (int32_t) p_pic_in->p[i_plane].i_visible_lines );
+ }
- /* Allocate structure */
- p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
- if( p_vout->p_sys == NULL )
+ vlc_mutex_lock( &p_sys->pce_lock );
+
+ /* manage the game, adjust locations, groups and regenerate some corrupted data if any */
+ for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 )
+ && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag
+ && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++)
{
- msg_Err( p_vout, "out of memory" );
- return VLC_ENOMEM;
+ puzzle_solve_pces_accuracy( p_filter );
}
- 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;
+ for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 )
+ && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag
+ && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++)
+ {
+ puzzle_solve_pces_group( p_filter );
+ }
- return VLC_SUCCESS;
-}
+ if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init
+ && p_sys->s_current_param.b_advanced )
+ puzzle_count_pce_group( p_filter);
+ if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init
+ && p_sys->s_current_param.b_advanced ) {
+ i_ret = puzzle_sort_layers( p_filter);
+ if (i_ret != VLC_SUCCESS)
+ {
+ vlc_mutex_unlock( &p_sys->pce_lock );
+ return CopyInfoAndRelease( p_pic_out, p_pic_in );
+ }
+ }
-/*****************************************************************************
- * 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 ) );
+ for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 24 )
+ && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag
+ && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++)
+ {
+ p_sys->i_calc_corn_loop++;
+ p_sys->i_calc_corn_loop %= p_sys->s_allocated.i_pieces_nbr;
+ puzzle_calculate_corners( p_filter, p_sys->i_calc_corn_loop );
+ }
- I_OUTPUTPICTURES = 0;
+ /* computer moves some piece depending on auto_solve and auto_shuffle param */
+ if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init
+ && p_sys->ps_puzzle_array != NULL && p_sys->s_current_param.b_advanced )
+ {
+ puzzle_auto_shuffle( p_filter );
+ puzzle_auto_solve( p_filter );
+ }
- /* 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;
+ vlc_mutex_unlock( &p_sys->pce_lock );
- p_vout->fmt_out = p_vout->fmt_in;
- fmt = p_vout->fmt_out;
+ /* draw output pic */
+ if ( !p_sys->b_bake_request && p_sys->b_init && p_sys->ps_puzzle_array != NULL ) {
- /* Try to open the real video output */
- msg_Dbg( p_vout, "spawning the real video output" );
+ puzzle_draw_borders(p_filter, p_pic_in, p_pic_out);
- p_vout->p_sys->p_vout = vout_Create( p_vout, &fmt );
+ p_sys->i_pointed_pce = NO_PCE;
+ puzzle_draw_pieces(p_filter, p_pic_in, p_pic_out);
- /* Everything failed */
- if( p_vout->p_sys->p_vout == NULL )
- {
- msg_Err( p_vout, "cannot open vout, aborting" );
- return VLC_EGENERIC;
- }
+ /* when puzzle_draw_pieces() has not updated p_sys->i_pointed_pce,
+ * use puzzle_find_piece to define the piece pointed by the mouse
+ */
+ if (p_sys->i_pointed_pce == NO_PCE)
+ p_sys->i_mouse_drag_pce = puzzle_find_piece( p_filter, p_sys->i_mouse_x, p_sys->i_mouse_y, -1);
+ else
+ p_sys->i_mouse_drag_pce = p_sys->i_pointed_pce;
- 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);
+ if (p_sys->s_current_param.b_preview )
+ puzzle_draw_preview(p_filter, p_pic_in, p_pic_out);
- ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
- ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
- ADD_PARENT_CALLBACKS( SendEventsToChild );
+ /* highlight the selected piece when not playing jigsaw mode */
+ if ( p_sys->i_selected != NO_PCE && !p_sys->s_current_param.b_blackslot
+ && !p_sys->s_current_param.b_advanced )
+ {
+ int32_t c = (p_sys->i_selected % p_sys->s_allocated.i_cols);
+ int32_t r = (p_sys->i_selected / p_sys->s_allocated.i_cols);
+
+ puzzle_draw_rectangle(p_pic_out,
+ p_sys->ps_puzzle_array[r][c][0].i_x,
+ p_sys->ps_puzzle_array[r][c][0].i_y,
+ p_sys->ps_puzzle_array[r][c][0].i_width,
+ p_sys->ps_puzzle_array[r][c][0].i_lines,
+ 255, 127, 127);
+ }
- return VLC_SUCCESS;
-}
+ /* draw the blackslot when playing sliding puzzle mode */
+ if ( p_sys->i_selected != NO_PCE && p_sys->s_current_param.b_blackslot
+ && !p_sys->s_current_param.b_advanced )
+ {
+ int32_t c = (p_sys->i_selected % p_sys->s_allocated.i_cols);
+ int32_t r = (p_sys->i_selected / p_sys->s_allocated.i_cols);
+
+ puzzle_fill_rectangle(p_pic_out,
+ p_sys->ps_puzzle_array[r][c][0].i_x,
+ p_sys->ps_puzzle_array[r][c][0].i_y,
+ p_sys->ps_puzzle_array[r][c][0].i_width,
+ p_sys->ps_puzzle_array[r][c][0].i_lines,
+ 0, 127, 127);
+ }
-/*****************************************************************************
- * End: terminate Magnify video thread output method
- *****************************************************************************/
-static void End( vout_thread_t *p_vout )
-{
- int i_index;
+ /* Draw the 'puzzle_shuffle' button if the puzzle is finished */
+ if ( p_sys->b_finished )
+ puzzle_draw_sign(p_pic_out, 0, 0, SHUFFLE_WIDTH, SHUFFLE_LINES, ppsz_shuffle_button, false);
- /* Free the fake output buffers we allocated */
- for( i_index = I_OUTPUTPICTURES ; i_index ; )
- {
- i_index--;
- free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
- }
+ /* draw an arrow at mouse pointer to indicate current action (rotation...) */
+ if ((p_sys->i_mouse_drag_pce != NO_PCE) && !p_sys->b_mouse_drag
+ && !p_sys->b_finished && p_sys->s_current_param.b_advanced )
+ {
+ vlc_mutex_lock( &p_sys->pce_lock );
- 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);
-}
+ int32_t i_delta_x;
-#define SHUFFLE_WIDTH 81
-#define SHUFFLE_HEIGHT 13
-static const char *shuffle_button[] =
-{
-".................................................................................",
-".............. ............................ ........ ...... ...............",
-".............. ........................... ......... ........ ...............",
-".............. ........................... ......... ........ ...............",
-".. ....... . ....... .... ...... ...... ...... ........ ...",
-". .... ...... ... ...... .... ....... ......... ........ ....... .. ..",
-". ........... .... ...... .... ....... ......... ........ ...... .... .",
-". ....... .... ...... .... ....... ......... ........ ...... .",
-".. ...... .... ...... .... ....... ......... ........ ...... .......",
-"...... ...... .... ...... .... ....... ......... ........ ...... .......",
-". .... ...... .... ...... ... ....... ......... ........ ....... .... .",
-".. ....... .... ....... . ....... ......... ........ ........ ..",
-"................................................................................."};
+ if (p_sys->s_current_param.i_rotate != 3)
+ i_delta_x = 0;
+ else if ( (p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_actual_angle & 1) == 0)
+ i_delta_x = p_sys->ps_desk_planes[0].i_pce_max_width / 6;
+ else
+ i_delta_x = p_sys->ps_desk_planes[0].i_pce_max_lines / 6;
+
+ if (p_sys->s_current_param.i_rotate == 0)
+ p_sys->i_mouse_action = 0;
+ else if (p_sys->s_current_param.i_rotate == 1)
+ p_sys->i_mouse_action = 2;
+ else if ( p_sys->i_mouse_x >= ( p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_center_x + i_delta_x) )
+ p_sys->i_mouse_action = -1; /* rotate counterclockwise */
+ else if ( p_sys->i_mouse_x <= ( p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_center_x - i_delta_x) )
+ p_sys->i_mouse_action = +1;
+ else
+ p_sys->i_mouse_action = 4; /* center click: only mirror */
+
+ if ( p_sys->i_mouse_action == +1 )
+ puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH,
+ p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_rot_arrow_sign, false);
+ else if ( p_sys->i_mouse_action == -1 )
+ puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH,
+ p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_rot_arrow_sign, true);
+ else if ( p_sys->i_mouse_action == 4 )
+ puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH,
+ p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_mir_arrow_sign, false);
+
+ vlc_mutex_unlock( &p_sys->pce_lock );
+ }
+ }
+ return CopyInfoAndRelease( p_pic_out, p_pic_in );
+}
/*****************************************************************************
- * Destroy: destroy Magnify video thread output method
+ * Misc stuff...
*****************************************************************************/
-static void Destroy( vlc_object_t *p_this )
+int puzzle_Callback( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *p_data )
{
- vout_thread_t *p_vout = (vout_thread_t *)p_this;
+ VLC_UNUSED(p_this); VLC_UNUSED(oldval);
+ filter_sys_t *p_sys = (filter_sys_t *)p_data;
- if( p_vout->p_sys->p_vout )
- {
- 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 );
+ vlc_mutex_lock( &p_sys->lock );
+ if( !strcmp( psz_var, CFG_PREFIX "rows" ) ) {
+ p_sys->s_new_param.i_rows = __MAX( 1, newval.i_int );
+ }
+ else if( !strcmp( psz_var, CFG_PREFIX "cols" ) ) {
+ p_sys->s_new_param.i_cols = __MAX( 1, newval.i_int );
+ }
+ else if( !strcmp( psz_var, CFG_PREFIX "border" ) ) {
+ p_sys->s_new_param.i_border = __MAX( 0, newval.i_int );
+ }
+ else if( !strcmp( psz_var, CFG_PREFIX "preview" ) ) {
+ p_sys->s_new_param.b_preview = newval.b_bool;
+ }
+ else if( !strcmp( psz_var, CFG_PREFIX "preview-size" ) ) {
+ p_sys->s_new_param.i_preview_size = newval.i_int;
+ }
+ else if( !strcmp( psz_var, CFG_PREFIX "shape-size" ) ) {
+ p_sys->s_new_param.i_shape_size = newval.i_int;
+ }
+ else if( !strcmp( psz_var, CFG_PREFIX "auto-shuffle" ) ) {
+ p_sys->s_new_param.i_auto_shuffle_speed = newval.i_int;
+ }
+ else if( !strcmp( psz_var, CFG_PREFIX "auto-solve" ) ) {
+ p_sys->s_new_param.i_auto_solve_speed = newval.i_int;
+ }
+ else if( !strcmp( psz_var, CFG_PREFIX "rotation" ) ) {
+ p_sys->s_new_param.i_rotate = newval.i_int;
+ }
+ else if( !strcmp( psz_var, CFG_PREFIX "mode" ) ) {
+ p_sys->s_new_param.i_mode = newval.i_int;
}
- image_HandlerDelete( p_vout->p_sys->p_image );
- free( p_vout->p_sys->pi_order );
-
- DEL_PARENT_CALLBACKS( SendEventsToChild );
+ p_sys->b_change_param = true;
+ vlc_mutex_unlock( &p_sys->lock );
- free( p_vout->p_sys );
+ return VLC_SUCCESS;
}
-/*****************************************************************************
- * Render: displays previously rendered output
- *****************************************************************************/
-static void Render( vout_thread_t *p_vout, picture_t *p_pic )
+/* mouse callback */
+int puzzle_mouse( filter_t *p_filter, vlc_mouse_t *p_mouse,
+ const vlc_mouse_t *p_old, const vlc_mouse_t *p_new )
{
- picture_t *p_outpic;
+ filter_sys_t *p_sys = p_filter->p_sys;
+ const video_format_t *p_fmt_in = &p_filter->fmt_in.video;
- //video_format_t fmt_out;
- // memset( &fmt_out, 0, sizeof(video_format_t) );
- //picture_t *p_converted;
+ /* Only take events inside the puzzle area */
+ if( p_new->i_x < 0 || p_new->i_x >= (int)p_fmt_in->i_width ||
+ p_new->i_y < 0 || p_new->i_y >= (int)p_fmt_in->i_height )
+ return VLC_EGENERIC;
- int i_plane;
+ if (! p_sys->b_init || p_sys->b_change_param) {
+ *p_mouse = *p_new;
+ return VLC_SUCCESS;
+ }
- int i_rows = p_vout->p_sys->i_rows;
- int i_cols = p_vout->p_sys->i_cols;
+ p_sys->i_mouse_x = p_new->i_x;
+ p_sys->i_mouse_y = p_new->i_y;
- /* 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 )
- {
- if( p_vout->b_die || p_vout->b_error )
+ /* If the puzzle is finished, shuffle it if needed */
+ if( p_sys->b_finished ) {
+ p_sys->b_mouse_drag = false;
+ p_sys->b_mouse_mvt = false;
+ if( vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT ) &&
+ p_new->i_x < SHUFFLE_WIDTH && p_new->i_y < SHUFFLE_LINES )
{
- return;
+ p_sys->b_shuffle_rqst = true;
+ return VLC_EGENERIC;
+ }
+ else
+ {
+ /* otherwise we can forward the mouse */
+ *p_mouse = *p_new;
+ return VLC_SUCCESS;
}
- msleep( VOUT_OUTMEM_SLEEP );
}
- vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
+ if ( !p_sys->s_current_param.b_advanced ) {
+ /* "square" game mode (sliding puzzle, swap...) */
+ const bool b_clicked = vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT );
- for( 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;
-
- for( i = 0; i < i_cols * i_rows; i++ )
+ if( b_clicked )
{
- 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 == VLC_TRUE
- && p_vout->p_sys->b_finished == VLC_FALSE
- && i == p_vout->p_sys->i_selected )
+ /* */
+ const int32_t i_border_width = p_fmt_in->i_width * p_sys->s_current_param.i_border / 100 / 2;
+ const int32_t i_border_height = p_fmt_in->i_height * p_sys->s_current_param.i_border / 100 / 2;
+ const int32_t i_pos_x = (p_new->i_x - i_border_width) * p_sys->s_allocated.i_cols / (p_fmt_in->i_width - 2*i_border_width);
+ const int32_t i_pos_y = (p_new->i_y - i_border_height) * p_sys->s_allocated.i_rows / (p_fmt_in->i_height - 2*i_border_height);
+
+ const int32_t i_pos = i_pos_y * p_sys->s_allocated.i_cols + i_pos_x;
+ p_sys->i_mouse_drag_pce = i_pos;
+
+ /* do not take into account if border clicked */
+ if ((p_new->i_x <= i_border_width) || (p_new->i_y <= i_border_height) || (p_new->i_x >= (int) p_fmt_in->i_width - i_border_width) || (p_new->i_y >= (int) p_fmt_in->i_height - i_border_height ) )
{
- uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
- for( ; i_row < i_last_row; i_row++, i_orow++ )
- {
- p_vout->p_libvlc->
- pf_memset( p_out->p_pixels + i_row * i_pitch
- + i_col * i_pitch / i_cols,
- color, i_pitch / i_cols );
- }
+ *p_mouse = *p_new;
+ return VLC_SUCCESS;
}
- else
+ else if( p_sys->i_selected == NO_PCE )
+ p_sys->i_selected = i_pos;
+ else if( p_sys->i_selected == i_pos && !p_sys->s_current_param.b_blackslot )
+ p_sys->i_selected = -1;
+ else if( ( p_sys->i_selected == i_pos + 1 && p_sys->i_selected%p_sys->s_allocated.i_cols != 0 )
+ || ( p_sys->i_selected == i_pos - 1 && i_pos % p_sys->s_allocated.i_cols != 0 )
+ || p_sys->i_selected == i_pos + p_sys->s_allocated.i_cols
+ || p_sys->i_selected == i_pos - p_sys->s_allocated.i_cols
+ || !p_sys->s_current_param.b_near )
+
{
- for( ; i_row < i_last_row; i_row++, i_orow++ )
+ /* Swap two pieces */
+ int32_t 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;
+
+ /* regen piece location from updated pi_order */
+ if ( p_sys->ps_pieces != NULL && p_sys->pi_order != NULL )
{
- p_vout->p_libvlc->
- pf_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 );
+ int32_t i = 0;
+ for (int32_t row = 0; row < p_sys->s_allocated.i_rows; row++) {
+ for (int32_t col = 0; col < p_sys->s_allocated.i_cols; col++) {
+ int32_t orow = p_sys->pi_order[i] / (p_sys->s_allocated.i_cols);
+ int32_t ocol = p_sys->pi_order[i] % (p_sys->s_allocated.i_cols);
+
+ p_sys->ps_pieces[i].i_original_row = orow;
+ p_sys->ps_pieces[i].i_original_col = ocol;
+ p_sys->ps_pieces[i].i_top_shape = 0;
+ p_sys->ps_pieces[i].i_btm_shape = 0;
+ p_sys->ps_pieces[i].i_right_shape = 0;
+ p_sys->ps_pieces[i].i_left_shape = 0;
+ p_sys->ps_pieces[i].i_actual_angle = 0;
+ p_sys->ps_pieces[i].i_actual_mirror = +1;
+ p_sys->ps_pieces[i].b_overlap = false;
+ p_sys->ps_pieces[i].b_finished = false;
+ p_sys->ps_pieces[i].i_group_ID = i;
+
+ for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) {
+ p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_width = p_sys->ps_puzzle_array[row][col][i_plane].i_width;
+ p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_lines = p_sys->ps_puzzle_array[row][col][i_plane].i_lines;
+ p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_original_x = p_sys->ps_puzzle_array[orow][ocol][i_plane].i_x;
+ p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_original_y = p_sys->ps_puzzle_array[orow][ocol][i_plane].i_y;
+ p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_actual_x = p_sys->ps_puzzle_array[row][col][i_plane].i_x;
+ p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_actual_y = p_sys->ps_puzzle_array[row][col][i_plane].i_y;
+ }
+ i++;
+ }
+ }
}
+
+ p_sys->i_selected = p_sys->s_current_param.b_blackslot ? i_pos : NO_PCE;
+ p_sys->b_finished = puzzle_is_finished( p_sys, p_sys->pi_order );
}
}
}
-
- if( p_vout->p_sys->i_selected != -1
- && p_vout->p_sys->b_blackslot == VLC_FALSE )
+ else /* jigsaw puzzle mode */
{
- 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;
- p_vout->p_libvlc->
- pf_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;
+ if ((p_sys->ps_desk_planes == NULL) || (p_sys->ps_pict_planes == NULL) || (p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL)) {
+ *p_mouse = *p_new;
+ return VLC_SUCCESS;
}
- i_row--;
- p_vout->p_libvlc->
- pf_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 == VLC_TRUE )
- {
- 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++ )
+ if( vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT ) )
{
- for( j = 0; j < SHUFFLE_WIDTH; j++ )
- {
- if( shuffle_button[i][j] == '.' )
- p_out->p_pixels[ i * i_pitch + j ] = 0xff;
- }
- }
- }
-
- vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
-}
-/*****************************************************************************
- * 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 )
-{
- var_Set( (vlc_object_t *)p_data, psz_var, newval );
+ vlc_mutex_lock( &p_sys->pce_lock );
- return VLC_SUCCESS;
-}
+ if (p_sys->i_mouse_drag_pce != NO_PCE) {
+ int i_ret = puzzle_piece_foreground( p_filter, p_sys->i_mouse_drag_pce);
+ if (i_ret != VLC_SUCCESS)
+ {
+ vlc_mutex_unlock( &p_sys->pce_lock );
+ return i_ret;
+ }
+ p_sys->i_mouse_drag_pce = 0;
+
+ uint32_t i_group_ID = p_sys->ps_pieces[0].i_group_ID;
+ for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
+ if ( i_group_ID == p_sys->ps_pieces[i].i_group_ID ) {
+ p_sys->ps_pieces[i].b_finished = false;
+ }
+ else {
+ break;
+ }
+ }
-/*****************************************************************************
- * 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 )
-{
- vout_thread_t *p_vout = (vout_thread_t *)p_this;
- var_Set( p_vout->p_sys->p_vout, psz_var, newval );
- return VLC_SUCCESS;
-}
+ p_sys->b_mouse_drag = true;
+ p_sys->b_mouse_mvt = false;
+ }
+ else {
+ /* player click an empty area then search a piece which is overlapping another one and place it here */
+ p_sys->b_mouse_drag = false;
+ for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++)
+ if ( p_sys->ps_pieces[i].b_overlap ) {
+ puzzle_move_group( p_filter, i, p_new->i_x - p_sys->ps_pieces[i].i_center_x, p_new->i_y - p_sys->ps_pieces[i].i_center_y );
+ p_sys->ps_pieces[i].b_overlap = false;
+ break;
+ }
+ p_sys->b_mouse_drag = false;
+ }
-/*****************************************************************************
- * 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 )
-{
- 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;
+ vlc_mutex_unlock( &p_sys->pce_lock );
- if( mouse & MOUSE_CLICKED )
- {
- 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 == VLC_TRUE
- && i_x < SHUFFLE_WIDTH && i_y < SHUFFLE_HEIGHT )
- {
- shuffle( p_vout->p_sys );
- }
- else if( p_vout->p_sys->i_selected == -1 )
- {
- p_vout->p_sys->i_selected = i_pos;
}
- else if( p_vout->p_sys->i_selected == i_pos
- && p_vout->p_sys->b_blackslot == VLC_FALSE )
+ else if( vlc_mouse_HasReleased( p_old, p_new, MOUSE_BUTTON_LEFT ) )
{
- p_vout->p_sys->i_selected = -1;
+ if ( !p_sys->b_mouse_mvt && p_sys->b_mouse_drag ) {
+ /* piece clicked without any mouse mvt => rotate it or mirror */
+ if ( p_sys->s_current_param.i_rotate != 0) {
+ vlc_mutex_lock( &p_sys->pce_lock );
+
+ uint32_t i_group_ID = p_sys->ps_pieces[0].i_group_ID;
+
+ for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++)
+ if ( i_group_ID == p_sys->ps_pieces[i].i_group_ID )
+ puzzle_rotate_pce( p_filter, i, p_sys->i_mouse_action, p_sys->ps_pieces[0].i_center_x, p_sys->ps_pieces[0].i_center_y, p_sys->i_mouse_action != 4 ? true : false );
+
+ vlc_mutex_unlock( &p_sys->pce_lock );
+ }
+ }
+ p_sys->b_mouse_drag = false;
+ p_sys->b_mouse_mvt = false;
}
- 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 )
+ else /* no action on left button */
{
- 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 == VLC_TRUE )
- p_vout->p_sys->i_selected = i_pos;
- else
- p_vout->p_sys->i_selected = -1;
+ /* check if the mouse is in the preview area */
+ switch ( p_sys->i_preview_pos )
+ {
+ case 0:
+ if ( p_new->i_x < (int)p_fmt_in->i_width / 2 && p_new->i_y < (int)p_fmt_in->i_height / 2 )
+ p_sys->i_preview_pos++;
+ break;
+ case 1:
+ if ( p_new->i_x > (int)p_fmt_in->i_width / 2 && p_new->i_y < (int)p_fmt_in->i_height / 2 )
+ p_sys->i_preview_pos++;
+ break;
+ case 2:
+ if ( p_new->i_x > (int)p_fmt_in->i_width / 2 && p_new->i_y > (int)p_fmt_in->i_height / 2 )
+ p_sys->i_preview_pos++;
+ break;
+ case 3:
+ if ( p_new->i_x < (int)p_fmt_in->i_width / 2 && p_new->i_y > (int)p_fmt_in->i_height / 2 )
+ p_sys->i_preview_pos++;
+ break;
+ }
+ p_sys->i_preview_pos %= 4;
- p_vout->p_sys->b_finished = finished( p_vout->p_sys );
- }
- }
- return VLC_SUCCESS;
-}
+ if ( !vlc_mouse_IsLeftPressed( p_new ) )
+ p_sys->b_mouse_drag = false;
-static int PuzzleCallback( vlc_object_t *p_this, char const *psz_var,
- vlc_value_t oldval, vlc_value_t newval,
- void *p_data )
-{
- vout_sys_t *p_sys = (vout_sys_t *)p_data;
- if( !strcmp( psz_var, CFG_PREFIX "rows" ) )
- {
- p_sys->i_rows = __MAX( 1, newval.i_int );
- }
- else if( !strcmp( psz_var, CFG_PREFIX "cols" ) )
- {
- p_sys->i_cols = __MAX( 1, newval.i_int );
- }
- else if( !strcmp( psz_var, CFG_PREFIX "black-slot" ) )
- {
- p_sys->b_blackslot = newval.b_bool;
+ int i_dx, i_dy;
+ vlc_mouse_GetMotion( &i_dx, &i_dy, p_old, p_new );
+ if ( i_dx != 0 || i_dy != 0 )
+ p_sys->b_mouse_mvt = true;
+
+ if (p_sys->b_mouse_drag) {
+ if ( ( p_new->i_x <= 0 ) || ( p_new->i_y <= 0 ) || ( p_new->i_x >= (int) p_fmt_in->i_width )
+ || ( p_new->i_y >= (int) p_fmt_in->i_height ) )
+ {
+ /* if the mouse is outside the window, stop moving the piece/group */
+ p_sys->b_mouse_drag = false;
+ p_sys->b_mouse_mvt = true;
+ }
+ else if ( i_dx != 0 || i_dy != 0 )
+ {
+ vlc_mutex_lock( &p_sys->pce_lock );
+
+ puzzle_move_group( p_filter, p_sys->i_mouse_drag_pce, i_dx, i_dy);
+
+ vlc_mutex_unlock( &p_sys->pce_lock );
+ }
+ }
+ }
}
- shuffle( p_sys );
- return VLC_SUCCESS;
+ return VLC_EGENERIC;
}