Commit 4b4f62a0 authored by Vianney BOYER's avatar Vianney BOYER Committed by Jean-Baptiste Kempf

Puzzle: main filter update

Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent b9730ca6
...@@ -52,6 +52,16 @@ if HAVE_GCRYPT ...@@ -52,6 +52,16 @@ if HAVE_GCRYPT
libvlc_LTLIBRARIES += libremoteosd_plugin.la libvlc_LTLIBRARIES += libremoteosd_plugin.la
endif endif
libpuzzle_plugin_la_SOURCES = \
puzzle.c puzzle.h \
puzzle_bezier.c puzzle_bezier.h \
puzzle_lib.c puzzle_lib.h \
puzzle_mgt.c puzzle_mgt.h \
puzzle_pce.c puzzle_pce.h
libpuzzle_plugin_la_CFLAGS = $(AM_CFLAGS)
libpuzzle_plugin_la_LIBADD = $(AM_LIBADD)
libvlc_LTLIBRARIES += libpuzzle_plugin.la
SOURCES_magnify = magnify.c SOURCES_magnify = magnify.c
SOURCES_wave = wave.c SOURCES_wave = wave.c
SOURCES_ripple = ripple.c SOURCES_ripple = ripple.c
...@@ -75,7 +85,6 @@ SOURCES_rotate = \ ...@@ -75,7 +85,6 @@ SOURCES_rotate = \
$(motion_extra) \ $(motion_extra) \
$(NULL) $(NULL)
SOURCES_puzzle = puzzle.c
SOURCES_colorthres = colorthres.c SOURCES_colorthres = colorthres.c
SOURCES_extract = extract.c SOURCES_extract = extract.c
SOURCES_sharpen = sharpen.c SOURCES_sharpen = sharpen.c
...@@ -149,7 +158,6 @@ libvlc_LTLIBRARIES += \ ...@@ -149,7 +158,6 @@ libvlc_LTLIBRARIES += \
libmotiondetect_plugin.la \ libmotiondetect_plugin.la \
libposterize_plugin.la \ libposterize_plugin.la \
libpsychedelic_plugin.la \ libpsychedelic_plugin.la \
libpuzzle_plugin.la \
libripple_plugin.la \ libripple_plugin.la \
librotate_plugin.la \ librotate_plugin.la \
librss_plugin.la \ librss_plugin.la \
......
...@@ -2,9 +2,11 @@ ...@@ -2,9 +2,11 @@
* puzzle.c : Puzzle game * puzzle.c : Puzzle game
***************************************************************************** *****************************************************************************
* Copyright (C) 2005-2009 VLC authors and VideoLAN * Copyright (C) 2005-2009 VLC authors and VideoLAN
* Copyright (C) 2013 Vianney Boyer
* $Id$ * $Id$
* *
* Authors: Antoine Cellerier <dionoea -at- videolan -dot- org> * 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 * 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 * under the terms of the GNU Lesser General Public License as published by
...@@ -37,6 +39,12 @@ ...@@ -37,6 +39,12 @@
#include "filter_picture.h" #include "filter_picture.h"
#include "puzzle.h"
#include "puzzle_bezier.h"
#include "puzzle_lib.h"
#include "puzzle_pce.h"
#include "puzzle_mgt.h"
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
*****************************************************************************/ *****************************************************************************/
...@@ -44,13 +52,32 @@ ...@@ -44,13 +52,32 @@
#define ROWS_LONGTEXT N_("Number of puzzle rows") #define ROWS_LONGTEXT N_("Number of puzzle rows")
#define COLS_TEXT N_("Number of puzzle columns") #define COLS_TEXT N_("Number of puzzle columns")
#define COLS_LONGTEXT N_("Number of puzzle columns") #define COLS_LONGTEXT N_("Number of puzzle columns")
#define BLACKSLOT_TEXT N_("Make one tile a black slot") #define MODE_TEXT N_("Game mode")
#define BLACKSLOT_LONGTEXT N_("Make one slot black. Other tiles can only be swapped with the black slot.") #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-" #define CFG_PREFIX "puzzle-"
static int Open ( vlc_object_t * ); int Open ( vlc_object_t * );
static void Close( vlc_object_t * ); void Close( vlc_object_t * );
vlc_module_begin() vlc_module_begin()
set_description( N_("Puzzle interactive game video filter") ) set_description( N_("Puzzle interactive game video filter") )
...@@ -63,107 +90,114 @@ vlc_module_begin() ...@@ -63,107 +90,114 @@ vlc_module_begin()
ROWS_TEXT, ROWS_LONGTEXT, false ) ROWS_TEXT, ROWS_LONGTEXT, false )
add_integer_with_range( CFG_PREFIX "cols", 4, 2, 16, add_integer_with_range( CFG_PREFIX "cols", 4, 2, 16,
COLS_TEXT, COLS_LONGTEXT, false ) COLS_TEXT, COLS_LONGTEXT, false )
add_bool( CFG_PREFIX "black-slot", false, add_integer_with_range( CFG_PREFIX "border", 3, 0, 40,
BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, false ) 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 ) set_callbacks( Open, Close )
vlc_module_end() vlc_module_end()
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
static const char *const ppsz_filter_options[] = {
"rows", "cols", "black-slot", NULL
};
static picture_t *Filter( filter_t *, picture_t * ); const char *const ppsz_filter_options[] = {
static int Mouse( filter_t *, vlc_mouse_t *, const vlc_mouse_t *, const vlc_mouse_t * ); "rows", "cols","border", "preview", "preview-size", "mode", "shape-size", "auto-shuffle", "auto-solve", "rotation", NULL
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;
/* */
struct
{
atomic_flag b_uptodate;
atomic_bool b_blackslot;
atomic_uint i_cols;
atomic_uint i_rows;
} change;
}; };
#define SHUFFLE_WIDTH 81
#define SHUFFLE_HEIGHT 13
static const char *shuffle_button[] =
{
".................................................................................",
".............. ............................ ........ ...... ...............",
".............. ........................... ......... ........ ...............",
".............. ........................... ......... ........ ...............",
".. ....... . ....... .... ...... ...... ...... ........ ...",
". .... ...... ... ...... .... ....... ......... ........ ....... .. ..",
". ........... .... ...... .... ....... ......... ........ ...... .... .",
". ....... .... ...... .... ....... ......... ........ ...... .",
".. ...... .... ...... .... ....... ......... ........ ...... .......",
"...... ...... .... ...... .... ....... ......... ........ ...... .......",
". .... ...... .... ...... ... ....... ......... ........ ....... .... .",
".. ....... .... ....... . ....... ......... ........ ........ ..",
"................................................................................."
};
/** /**
* Open the filter * Open the filter
*/ */
static int Open( vlc_object_t *p_this ) int Open( vlc_object_t *p_this )
{ {
filter_t *p_filter = (filter_t *)p_this; filter_t *p_filter = (filter_t *)p_this;
filter_sys_t *p_sys; filter_sys_t *p_sys;
/* */ /* Assert video in match with video out */
if( !es_format_IsSimilar( &p_filter->fmt_in, &p_filter->fmt_out ) ) if( !es_format_IsSimilar( &p_filter->fmt_in, &p_filter->fmt_out ) ) {
{
msg_Err( p_filter, "Input and output format does not match" ); msg_Err( p_filter, "Input and output format does not match" );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
/* Allocate structure */ /* Allocate structure */
p_filter->p_sys = p_sys = malloc( sizeof( *p_sys ) ); p_filter->p_sys = p_sys = calloc(1, sizeof( *p_sys ) );
if( !p_sys ) if( !p_sys )
return VLC_ENOMEM; return VLC_ENOMEM;
config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options, /* init some values */
p_filter->p_cfg ); 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;
p_sys->pi_order = NULL; /* 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 )
{
free(p_filter->p_sys);
p_filter->p_sys = NULL;
return VLC_ENOMEM;
}
for (int32_t i_shape = 0; i_shape<SHAPES_QTY; i_shape++)
p_sys->ps_bezier_pts_H[i_shape] = puzzle_rand_bezier(7);
atomic_init( &p_sys->change.i_rows,
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "rows" ) );
atomic_init( &p_sys->change.i_cols,
var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "cols" ) );
atomic_init( &p_sys->change.b_blackslot,
var_CreateGetBoolCommand( p_filter, CFG_PREFIX "black-slot" ) );
p_sys->change.b_uptodate = ATOMIC_FLAG_INIT;
var_AddCallback( p_filter, CFG_PREFIX "rows", PuzzleCallback, p_sys ); config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
var_AddCallback( p_filter, CFG_PREFIX "cols", PuzzleCallback, p_sys ); p_filter->p_cfg );
var_AddCallback( p_filter, CFG_PREFIX "black-slot", PuzzleCallback, p_sys );
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_filter = Filter;
p_filter->pf_video_mouse = Mouse; p_filter->pf_video_mouse = puzzle_mouse;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -171,271 +205,644 @@ static int Open( vlc_object_t *p_this ) ...@@ -171,271 +205,644 @@ static int Open( vlc_object_t *p_this )
/** /**
* Close the filter * Close the filter
*/ */
static void Close( vlc_object_t *p_this ) void Close( vlc_object_t *p_this ) {
{
filter_t *p_filter = (filter_t *)p_this; filter_t *p_filter = (filter_t *)p_this;
filter_sys_t *p_sys = p_filter->p_sys; 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 "rows", puzzle_Callback, p_sys );
var_DelCallback( p_filter, CFG_PREFIX "cols", PuzzleCallback, p_sys ); var_DelCallback( p_filter, CFG_PREFIX "cols", puzzle_Callback, p_sys );
var_DelCallback( p_filter, CFG_PREFIX "black-slot", PuzzleCallback, 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 ); 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 ); free( p_sys );
} }
/** /**
* Filter a picture * Filter a picture
*/ */
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) 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; filter_sys_t *p_sys = p_filter->p_sys;
picture_t *p_outpic = filter_NewPicture( p_filter ); picture_t *p_pic_out = filter_NewPicture( p_filter );
if( !p_outpic ) if( !p_pic_out ) {
{ picture_Release( p_pic_in );
picture_Release( p_pic );
return NULL; return NULL;
} }
/* */ int i_ret = 0;
if( !atomic_flag_test_and_set( &p_sys->change.b_uptodate ) ) p_sys->b_bake_request = false;
{
p_sys->i_rows = atomic_load( &p_sys->change.i_rows ); 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->i_cols = atomic_load( &p_sys->change.i_cols ); p_sys->b_init = false;
p_sys->b_blackslot = atomic_load( &p_sys->change.b_blackslot );
Shuffle( p_sys ); 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;
const int i_rows = p_sys->i_rows; p_sys->s_current_param.i_pict_height = (int) p_pic_in->p[0].i_visible_lines;
const int i_cols = p_sys->i_cols; 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;
/* Draw each piece of the puzzle at the right place */ /* assert no mismatch between sizes */
for( int i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ ) 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
const plane_t *p_in = &p_pic->p[i_plane]; || p_sys->s_current_param.i_pict_width != (int) p_fmt_in->i_width
plane_t *p_out = &p_outpic->p[i_plane]; || p_sys->s_current_param.i_pict_height != (int) p_fmt_in->i_height )
return NULL;
for( int i = 0; i < i_cols * i_rows; i++ )
{
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; vlc_mutex_lock( &p_sys->lock );
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; /* check if we have to compute initial data */
int i_orow = (p_sys->pi_order[i] / i_cols) * i_piece_height; 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 )
{
p_sys->b_bake_request = true;
p_sys->b_init = false;
p_sys->b_shuffle_rqst = true;
p_sys->b_shape_init = false;
}
if( p_sys->b_blackslot && !p_sys->b_finished && i == p_sys->i_selected ) 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 )
uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 ); {
for( int r = i_row; r < i_last_row; r++ ) p_sys->b_bake_request = true;
{ p_sys->b_shape_init = false;
memset( p_out->p_pixels + r * p_out->i_pitch + i_col, }
color, i_piece_width );
}
}
else
{
for( int r = i_row, or = i_orow; r < i_last_row; r++, or++ )
{
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 );
}
}
/* Draw the borders of the selected slot */ /* depending on the game selected, set associated internal flags */
if( i_plane == 0 && !p_sys->b_blackslot && p_sys->i_selected == i ) switch ( p_sys->s_new_param.i_mode )
{ {
memset( p_out->p_pixels + i_row * p_out->i_pitch + i_col, case 0: /* jigsaw puzzle */
0xff, i_piece_width ); p_sys->s_new_param.b_advanced = true;
for( int r = i_row; r < i_last_row; r++ ) p_sys->s_new_param.b_blackslot = false;
{ p_sys->s_new_param.b_near = false;
p_out->p_pixels[r * p_out->i_pitch + i_col + 0 + 0 ] = 0xff; break;
p_out->p_pixels[r * p_out->i_pitch + i_col + i_piece_width - 1 ] = 0xff; case 1: /* sliding puzzle */
} p_sys->s_new_param.b_advanced = false;
memset( p_out->p_pixels + (i_last_row - 1) * p_out->i_pitch + i_col, p_sys->s_new_param.b_blackslot = true;
0xff, i_piece_width ); 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;
}
else
{
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_change_param = false;
} }
/* Draw the 'Shuffle' button if the puzzle is finished */ vlc_mutex_unlock( &p_sys->lock );
if( p_sys->b_finished )
{ /* generate initial puzzle data when needed */
plane_t *p_out = &p_outpic->p[Y_PLANE]; if ( p_sys->b_bake_request ) {
for( int i = 0; i < SHUFFLE_HEIGHT; i++ ) if (!p_sys->b_shuffle_rqst) {
{ /* here we have to keep the same position
for( int j = 0; j < SHUFFLE_WIDTH; j++ ) * 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 )
{ {
if( shuffle_button[i][j] == '.' ) free(ps_save_game->ps_pieces);
p_out->p_pixels[ i * p_out->i_pitch + j ] = 0xff; 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 );
} }
} }
return CopyInfoAndRelease( p_outpic, p_pic ); /* 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 );
}
static int Mouse( filter_t *p_filter, vlc_mouse_t *p_mouse, /* preset output pic */
const vlc_mouse_t *p_old, const vlc_mouse_t *p_new ) 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);
filter_sys_t *p_sys = p_filter->p_sys; else {
const video_format_t *p_fmt = &p_filter->fmt_in.video; /* 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 );
}
/* Only take events inside the puzzle erea */ vlc_mutex_lock( &p_sys->pce_lock );
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;
/* */ /* manage the game, adjust locations, groups and regenerate some corrupted data if any */
const bool b_clicked = vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT ); 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_accuracy( p_filter );
}
/* If the puzzle is finished, shuffle it if needed */ for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 )
if( p_sys->b_finished ) && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag
&& p_sys->b_init && p_sys->s_current_param.b_advanced ); i++)
{ {
if( b_clicked && puzzle_solve_pces_group( p_filter );
p_new->i_x < SHUFFLE_WIDTH && p_new->i_y < SHUFFLE_HEIGHT )
{
atomic_flag_clear( &p_sys->change.b_uptodate );
return VLC_EGENERIC;
}
else
{
/* This is the only case where we can forward the mouse */
*p_mouse = *p_new;
return VLC_SUCCESS;
}
} }
if( !b_clicked )
return VLC_EGENERIC;
/* */ if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init
const int i_pos_x = p_new->i_x * p_sys->i_cols / p_fmt->i_width; && p_sys->s_current_param.b_advanced )
const int i_pos_y = p_new->i_y * p_sys->i_rows / p_fmt->i_height; puzzle_count_pce_group( p_filter);
const int i_pos = i_pos_y * p_sys->i_cols + i_pos_x; 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)
return CopyInfoAndRelease( p_pic_out, p_pic_in );
}
if( p_sys->i_selected == -1 ) 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_selected = i_pos; 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 );
} }
else if( p_sys->i_selected == i_pos && !p_sys->b_blackslot )
/* 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 )
{ {
p_sys->i_selected = -1; puzzle_auto_shuffle( p_filter );
puzzle_auto_solve( p_filter );
} }
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; vlc_mutex_unlock( &p_sys->pce_lock );
p_sys->b_finished = IsFinished( p_sys );
/* draw output pic */
if ( !p_sys->b_bake_request && p_sys->b_init && p_sys->ps_puzzle_array != NULL ) {
puzzle_draw_borders(p_filter, p_pic_in, p_pic_out);
p_sys->i_pointed_pce = NO_PCE;
puzzle_draw_pieces(p_filter, p_pic_in, p_pic_out);
/* 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;
if (p_sys->s_current_param.b_preview )
puzzle_draw_preview(p_filter, p_pic_in, p_pic_out);
/* 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);
}
/* 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);
}
/* 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);
/* 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 );
int32_t i_delta_x;
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 VLC_EGENERIC;
return CopyInfoAndRelease( p_pic_out, p_pic_in );
} }
/***************************************************************************** /*****************************************************************************
* Misc stuff... * Misc stuff...
*****************************************************************************/ *****************************************************************************/
static int PuzzleCallback( vlc_object_t *p_this, char const *psz_var, int puzzle_Callback( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, vlc_value_t oldval, vlc_value_t newval,
void *p_data ) void *p_data )
{ {
VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(p_this); VLC_UNUSED(oldval);
filter_sys_t *p_sys = 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->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;
}
if( !strcmp( psz_var, CFG_PREFIX "rows" ) ) p_sys->b_change_param = true;
atomic_store( &p_sys->change.i_rows, __MAX( 2, newval.i_int ) ); vlc_mutex_unlock( &p_sys->lock );
else if( !strcmp( psz_var, CFG_PREFIX "cols" ) )
atomic_store( &p_sys->change.i_cols, __MAX( 2, newval.i_int ) );
else if( !strcmp( psz_var, CFG_PREFIX "black-slot" ) )
atomic_store( &p_sys->change.b_blackslot, newval.b_bool );
atomic_flag_clear( &p_sys->change.b_uptodate );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
static bool IsFinished( filter_sys_t *p_sys ) /* 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 )
{ {
for( int i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ ) filter_sys_t *p_sys = p_filter->p_sys;
{ const video_format_t *p_fmt_in = &p_filter->fmt_in.video;
if( i != p_sys->pi_order[i] )
return false;
}
return true;
}
static bool IsValid( filter_sys_t *p_sys ) /* Only take events inside the puzzle area */
{ if( p_new->i_x < 0 || p_new->i_x >= (int)p_fmt_in->i_width ||
const int i_count = p_sys->i_cols * p_sys->i_rows; p_new->i_y < 0 || p_new->i_y >= (int)p_fmt_in->i_height )
return VLC_EGENERIC;
if( !p_sys->b_blackslot ) if (! p_sys->b_init || p_sys->b_change_param) {
return true; *p_mouse = *p_new;
return VLC_SUCCESS;
}
int d = 0; p_sys->i_mouse_x = p_new->i_x;
for( int i = 0; i < i_count; i++ ) p_sys->i_mouse_y = p_new->i_y;
{
if( p_sys->pi_order[i] == i_count - 1 ) /* 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 )
{ {
d += i / p_sys->i_cols + 1; p_sys->b_shuffle_rqst = true;
continue; return VLC_EGENERIC;
} }
for( int j = i+1; j < i_count; j++ ) else
{ {
if( p_sys->pi_order[j] == i_count - 1 ) /* otherwise we can forward the mouse */
continue; *p_mouse = *p_new;
if( p_sys->pi_order[i] > p_sys->pi_order[j] ) return VLC_SUCCESS;
d++;
} }
} }
return (d%2) == 0;
}
static void Shuffle( filter_sys_t *p_sys ) if ( !p_sys->s_current_param.b_advanced ) {
{ /* "square" game mode (sliding puzzle, swap...) */
const unsigned i_count = p_sys->i_cols * p_sys->i_rows; const bool b_clicked = vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT );
free( p_sys->pi_order ); if( b_clicked )
{
/* */
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;
p_sys->pi_order = calloc( i_count, sizeof(*p_sys->pi_order) ); /* do not take into account if border clicked */
do 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 ) )
{
*p_mouse = *p_new;
return VLC_SUCCESS;
}
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 )
{
/* 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 )
{
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 );
}
}
}
else /* jigsaw puzzle mode */
{ {
for( unsigned i = 0; i < i_count; i++ ) 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_sys->pi_order[i] = -1; *p_mouse = *p_new;
return VLC_SUCCESS;
}
for( unsigned c = 0; c < i_count; ) if( vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT ) )
{ {
unsigned i = ((unsigned)vlc_mrand48()) % i_count;
if( p_sys->pi_order[i] == -1 ) vlc_mutex_lock( &p_sys->pce_lock );
p_sys->pi_order[i] = c++;
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)
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;
}
}
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;
}
vlc_mutex_unlock( &p_sys->pce_lock );
} }
p_sys->b_finished = IsFinished( p_sys ); else if( vlc_mouse_HasReleased( p_old, p_new, MOUSE_BUTTON_LEFT ) )
{
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 );
} while( p_sys->b_finished || !IsValid( p_sys ) ); uint32_t i_group_ID = p_sys->ps_pieces[0].i_group_ID;
if( p_sys->b_blackslot ) 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 )
for( unsigned i = 0; i < i_count; i++ ) 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 /* no action on left button */
{ {
if( p_sys->pi_order[i] == (int)i_count - 1 ) /* check if the mouse is in the preview area */
switch ( p_sys->i_preview_pos )
{ {
p_sys->i_selected = i; 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; break;
} }
p_sys->i_preview_pos %= 4;
if ( !vlc_mouse_IsLeftPressed( p_new ) )
p_sys->b_mouse_drag = false;
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 );
}
}
} }
} }
else return VLC_EGENERIC;
{
p_sys->i_selected = -1;
}
} }
/*****************************************************************************
* puzzle.h : Puzzle game
*****************************************************************************
* Copyright (C) 2005-2009 VLC authors and VideoLAN
* Copyright (C) 2013 Vianney Boyer
* $Id$
*
* Authors: 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 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 Lesser General Public License for more details.
*
* 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.
*****************************************************************************/
#ifndef VLC_PUZZLE_H
#define VLC_PUZZLE_H 1
#include "puzzle_mgt.h"
struct filter_sys_t {
bool b_init;
bool b_bake_request;
bool b_shape_init;
bool b_change_param;
bool b_finished;
bool b_shuffle_rqst;
bool b_mouse_drag;
bool b_mouse_mvt;
param_t s_allocated;
param_t s_current_param;
param_t s_new_param;
uint32_t i_done_count, i_tmp_done_count;
int32_t i_mouse_drag_pce;
int32_t i_mouse_x, i_mouse_y;
int16_t i_pointed_pce;
int8_t i_mouse_action;
uint32_t i_solve_acc_loop, i_solve_grp_loop, i_calc_corn_loop;
int32_t i_magnet_accuracy;
int32_t *pi_group_qty;
int32_t *pi_order; /* array which contains final pieces location (used in BASIC GAME MODE) */
puzzle_array_t ***ps_puzzle_array; /* array [row][col][plane] preset of location & size of each piece in the original image */
piece_shape_t **ps_pieces_shapes; /* array [each piece type (PCE_TYPE_NBR * negative * 4: top...)][each plane] of piece definition */
piece_t *ps_pieces; /* list [piece] of pieces data. */
piece_t *ps_pieces_tmp; /* used when sorting layers */
puzzle_plane_t *ps_desk_planes;
puzzle_plane_t *ps_pict_planes;
uint8_t i_preview_pos;
int32_t i_selected;
vlc_mutex_t lock, pce_lock;
int32_t i_auto_shuffle_countdown_val, i_auto_solve_countdown_val;
point_t **ps_bezier_pts_H;
};
picture_t *Filter( filter_t *, picture_t * );
int puzzle_Callback( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );
int puzzle_mouse( filter_t *, vlc_mouse_t *, const vlc_mouse_t *, const vlc_mouse_t * );
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment