[vlc-devel] [PATCH] Puzzle filter enhancement

vlcvboyer vlcvboyer at gmail.com
Thu Jan 17 07:55:08 CET 2013


Hi,

I've modified the original puzzle filter and added some additional features:
- "puzzle style" piece shapes
- pieces rotations and mirror
- drag'n drop with mouse to manipulate pieces
- a preview can be displayed in a corner
- borders can be shown
- auto solve (to make it easier...)
- auto shuffle (...to increase difficulty)

Original puzzle filter is still available. You just have to disable
"advanced mode" parameter.

I hope you'll appreciate it and include it in the current code.

Regards

Vianney


Date: Wed, 16 Jan 2013 22:44:13 +0100
Subject: [PATCH] Puzzle filter enhancement

---
 AUTHORS                                        |    1 +
 modules/gui/qt4/components/extended_panels.cpp |   10 +
 modules/gui/qt4/ui/video_effects.ui            |  335 ++-
 modules/video_filter/puzzle.c                  | 3517
++++++++++++++++++++++--
 4 files changed, 3575 insertions(+), 288 deletions(-)
 mode change 100644 => 100755 AUTHORS
 mode change 100644 => 100755 modules/gui/qt4/components/extended_panels.cpp
 mode change 100644 => 100755 modules/gui/qt4/ui/video_effects.ui
 mode change 100644 => 100755 modules/video_filter/puzzle.c

diff --git a/AUTHORS b/AUTHORS
old mode 100644
new mode 100755
index eac402c..6ffcd40
--- a/AUTHORS
+++ b/AUTHORS
@@ -557,6 +557,7 @@ Tim Schuerewegen
 Tong Ka Man
 Torsten Spindler
 Udo Richter
+Vianney Boyer
 Vincent Dimar
 Vincent Penne
 Vitalijus Slavinskas
diff --git a/modules/gui/qt4/components/extended_panels.cpp
b/modules/gui/qt4/components/extended_panels.cpp
old mode 100644
new mode 100755
index f6b28c9..48f64b0
--- a/modules/gui/qt4/components/extended_panels.cpp
+++ b/modules/gui/qt4/components/extended_panels.cpp
@@ -188,6 +188,15 @@ ExtVideo::ExtVideo( intf_thread_t *_p_intf, QTabWidget
*_parent ) :
     SETUP_VFILTER_OPTION( puzzleRowsSpin, valueChanged( int ) )
     SETUP_VFILTER_OPTION( puzzleColsSpin, valueChanged( int ) )
     SETUP_VFILTER_OPTION( puzzleBlackSlotCheck, stateChanged( int ) )
+    SETUP_VFILTER_OPTION( puzzleNearCheck, stateChanged( int ) )
+    SETUP_VFILTER_OPTION( puzzleBorderSlider, valueChanged( int ) )
+    SETUP_VFILTER_OPTION( puzzlePreviewCheck, stateChanged( int ) )
+    SETUP_VFILTER_OPTION( puzzlePreviewSizeSlider, valueChanged( int ) )
+    SETUP_VFILTER_OPTION( puzzleShapeSizeSlider, valueChanged( int ) )
+    SETUP_VFILTER_OPTION( puzzleAdvancedGameCheck, stateChanged( int ) )
+    SETUP_VFILTER_OPTION( puzzleAutoShuffleSlider, valueChanged( int ) )
+    SETUP_VFILTER_OPTION( puzzleAutoSolveSlider, valueChanged( int ) )
+    SETUP_VFILTER_OPTION( puzzleRotationCombo, currentIndexChanged( int ) )
 
     SETUP_VFILTER( magnify )
 
@@ -1398,6 +1407,7 @@ Compressor::Compressor( intf_thread_t *p_intf, QWidget
*parent )
  * Spatializer
  **********************************************************************/
 
+
 Spatializer::Spatializer( intf_thread_t *p_intf, QWidget *parent )
     : AudioFilterControlWidget( p_intf, parent, "spatializer" )
 {
diff --git a/modules/gui/qt4/ui/video_effects.ui
b/modules/gui/qt4/ui/video_effects.ui
old mode 100644
new mode 100755
index 2d21e43..1b3b42f
--- a/modules/gui/qt4/ui/video_effects.ui
+++ b/modules/gui/qt4/ui/video_effects.ui
@@ -864,80 +864,6 @@
       </layout>
      </widget>
     </item>
-    <item row="3" column="1">
-     <widget class="QGroupBox" name="puzzleEnable">
-      <property name="title">
-       <string>Puzzle game</string>
-      </property>
-      <property name="checkable">
-       <bool>true</bool>
-      </property>
-      <property name="checked">
-       <bool>false</bool>
-      </property>
-      <layout class="QGridLayout" name="gridLayout_3">
-       <item row="0" column="0">
-        <widget class="QLabel" name="label_27">
-         <property name="text">
-          <string>Rows</string>
-         </property>
-         <property name="buddy">
-          <cstring>puzzleRowsSpin</cstring>
-         </property>
-        </widget>
-       </item>
-       <item row="0" column="1">
-        <widget class="QSpinBox" name="puzzleRowsSpin">
-         <property name="alignment">
-          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-         </property>
-         <property name="minimum">
-          <number>2</number>
-         </property>
-         <property name="maximum">
-          <number>16</number>
-         </property>
-         <property name="value">
-          <number>4</number>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="0">
-        <widget class="QLabel" name="label_26">
-         <property name="text">
-          <string>Columns</string>
-         </property>
-         <property name="buddy">
-          <cstring>puzzleColsSpin</cstring>
-         </property>
-        </widget>
-       </item>
-       <item row="1" column="1">
-        <widget class="QSpinBox" name="puzzleColsSpin">
-         <property name="alignment">
-          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-         </property>
-         <property name="minimum">
-          <number>2</number>
-         </property>
-         <property name="maximum">
-          <number>16</number>
-         </property>
-         <property name="value">
-          <number>4</number>
-         </property>
-        </widget>
-       </item>
-       <item row="2" column="0" colspan="2">
-        <widget class="QCheckBox" name="puzzleBlackSlotCheck">
-         <property name="text">
-          <string>Black slot</string>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </widget>
-    </item>
    </layout>
   </widget>
   <widget class="QWidget" name="tab_8">
@@ -1794,6 +1720,264 @@
     </item>
    </layout>
   </widget>
+  <widget class="QWidget" name="tab_4">
+   <attribute name="title">
+    <string>Puzzle</string>
+   </attribute>
+   <widget class="QGroupBox" name="puzzleEnable">
+    <property name="geometry">
+     <rect>
+      <x>10</x>
+      <y>10</y>
+      <width>521</width>
+      <height>241</height>
+     </rect>
+    </property>
+    <property name="sizePolicy">
+     <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+      <horstretch>0</horstretch>
+      <verstretch>0</verstretch>
+     </sizepolicy>
+    </property>
+    <property name="title">
+     <string>Puzzle</string>
+    </property>
+    <property name="checkable">
+     <bool>true</bool>
+    </property>
+    <property name="checked">
+     <bool>false</bool>
+    </property>
+    <layout class="QGridLayout" name="gridLayout_21">
+     <item row="2" column="1">
+      <widget class="QLabel" name="label_44">
+       <property name="text">
+        <string>Rotate</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QSpinBox" name="puzzleColsSpin">
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+       <property name="suffix">
+        <string> col</string>
+       </property>
+       <property name="minimum">
+        <number>1</number>
+       </property>
+       <property name="maximum">
+        <number>20</number>
+       </property>
+       <property name="value">
+        <number>4</number>
+       </property>
+      </widget>
+     </item>
+     <item row="17" column="0">
+      <widget class="QLabel" name="label_33">
+       <property name="text">
+        <string>Auto solve</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="1" colspan="4">
+      <widget class="QSlider" name="puzzlePreviewSizeSlider">
+       <property name="maximum">
+        <number>100</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="tickPosition">
+        <enum>QSlider::TicksBelow</enum>
+       </property>
+       <property name="tickInterval">
+        <number>10</number>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="0">
+      <widget class="QCheckBox" name="puzzleAdvancedGameCheck">
+       <property name="text">
+        <string>Advanced mode</string>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="0">
+      <widget class="QSpinBox" name="puzzleRowsSpin">
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+       <property name="suffix">
+        <string> row</string>
+       </property>
+       <property name="prefix">
+        <string/>
+       </property>
+       <property name="minimum">
+        <number>1</number>
+       </property>
+       <property name="maximum">
+        <number>20</number>
+       </property>
+       <property name="value">
+        <number>4</number>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="1" colspan="4">
+      <widget class="QSlider" name="puzzleShapeSizeSlider">
+       <property name="maximum">
+        <number>100</number>
+       </property>
+       <property name="pageStep">
+        <number>5</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="tickPosition">
+        <enum>QSlider::TicksBelow</enum>
+       </property>
+       <property name="tickInterval">
+        <number>5</number>
+       </property>
+      </widget>
+     </item>
+     <item row="4" column="0">
+      <widget class="QCheckBox" name="puzzlePreviewCheck">
+       <property name="text">
+        <string>Preview</string>
+       </property>
+      </widget>
+     </item>
+     <item row="6" column="0">
+      <widget class="QLabel" name="label_45">
+       <property name="text">
+        <string>shape size</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="0">
+      <widget class="QLabel" name="label_26">
+       <property name="text">
+        <string>border</string>
+       </property>
+      </widget>
+     </item>
+     <item row="18" column="0">
+      <widget class="QLabel" name="label_27">
+       <property name="layoutDirection">
+        <enum>Qt::LeftToRight</enum>
+       </property>
+       <property name="text">
+        <string>Auto shuffle</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="17" column="1" colspan="4">
+      <widget class="QSlider" name="puzzleAutoSolveSlider">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximum">
+        <number>30000</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="tickPosition">
+        <enum>QSlider::TicksBelow</enum>
+       </property>
+       <property name="tickInterval">
+        <number>1000</number>
+       </property>
+      </widget>
+     </item>
+     <item row="18" column="1" colspan="4">
+      <widget class="QSlider" name="puzzleAutoShuffleSlider">
+       <property name="maximum">
+        <number>30000</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="tickPosition">
+        <enum>QSlider::TicksBelow</enum>
+       </property>
+       <property name="tickInterval">
+        <number>1000</number>
+       </property>
+      </widget>
+     </item>
+     <item row="3" column="1" colspan="4">
+      <widget class="QSlider" name="puzzleBorderSlider">
+       <property name="maximum">
+        <number>25</number>
+       </property>
+       <property name="pageStep">
+        <number>5</number>
+       </property>
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="tickPosition">
+        <enum>QSlider::TicksBelow</enum>
+       </property>
+       <property name="tickInterval">
+        <number>5</number>
+       </property>
+      </widget>
+     </item>
+     <item row="2" column="2" colspan="3">
+      <widget class="QComboBox" name="puzzleRotationCombo"/>
+     </item>
+     <item row="1" column="0">
+      <widget class="QLabel" name="label_46">
+       <property name="text">
+        <string>basic mode parameters:</string>
+       </property>
+       <property name="alignment">
+        <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="1">
+      <widget class="QCheckBox" name="puzzleNearCheck">
+       <property name="text">
+        <string>Ajoining only</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="2">
+      <widget class="QCheckBox" name="puzzleBlackSlotCheck">
+       <property name="text">
+        <string>Black slot</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </widget>
+   <zorder>puzzleEnable</zorder>
+   <zorder>puzzleAutoShuffleSlider</zorder>
+  </widget>
  </widget>
  <tabstops>
   <tabstop>adjustEnable</tabstop>
@@ -1816,9 +2000,6 @@
   <tabstop>rotateEnable</tabstop>
   <tabstop>rotateAngleDial</tabstop>
   <tabstop>transformTypeCombo</tabstop>
-  <tabstop>puzzleRowsSpin</tabstop>
-  <tabstop>puzzleColsSpin</tabstop>
-  <tabstop>puzzleBlackSlotCheck</tabstop>
   <tabstop>colorthresEnable</tabstop>
   <tabstop>colorthresColorText</tabstop>
   <tabstop>colorthresSaturationthresSlider</tabstop>
diff --git a/modules/video_filter/puzzle.c b/modules/video_filter/puzzle.c
old mode 100644
new mode 100755
index 713d1f2..60c210c
--- a/modules/video_filter/puzzle.c
+++ b/modules/video_filter/puzzle.c
@@ -5,6 +5,7 @@
  * $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 Lesser General Public License as published by
@@ -35,8 +36,21 @@
 #include <vlc_filter.h>
 #include <vlc_rand.h>
 
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
 #include "filter_picture.h"
 
+#ifndef MAX
+# define MAX(x,y) ((x>y) ? x : y)
+#endif
+#ifndef MIN
+# define MIN(x,y) ((x<y) ? x : y)
+#endif
+
+#define init_countdown(init_val) ( (MAX( 1, 30000 - init_val)/20) / 2 + (
(unsigned) vlc_mrand48() ) % ( MAX( 1, ((30000 - init_val)/20) ) ) )
+
 
/***************************************************************************
**
  * Module descriptor
 
****************************************************************************
*/
@@ -46,9 +60,33 @@
 #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 NEAR_TEXT N_("Near")
+#define NEAR_LONGTEXT N_("Can only change two touching tiles.")
+#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 ADVANCED_GAME_TEXT N_("Advanced game mode")
+#define ADVANCED_GAME_LONGTEXT N_("Advanced game mode with curved shapes,
rotation, drag'n drop...")
+#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")
+
+static const int pi_rotation_values[] = { (int) 0, (int) 1, (int) 2, (int)
3 };
+static 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 SHAPES_QTY 20
+#define PIECE_TYPE_NBR (4*2*(1+SHAPES_QTY))
+
 static int  Open ( vlc_object_t * );
 static void Close( vlc_object_t * );
 
@@ -65,65 +103,271 @@ vlc_module_begin()
                             COLS_TEXT, COLS_LONGTEXT, false )
     add_bool( CFG_PREFIX "black-slot", false,
               BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, false )
+    add_bool( CFG_PREFIX "near", false,
+              NEAR_TEXT, NEAR_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_bool( CFG_PREFIX "advanced-game", true,
+              ADVANCED_GAME_TEXT, ADVANCED_GAME_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
)
 
     set_callbacks( Open, Close )
 vlc_module_end()
 
-
 
/***************************************************************************
**
  * Local prototypes
 
****************************************************************************
*/
+
 static const char *const ppsz_filter_options[] = {
-    "rows", "cols", "black-slot", NULL
+    "rows", "cols", "black-slot", "near", "border", "preview",
"preview-size", "advanced-game", "shape-size", "auto-shuffle", "auto-solve",
"rotation", NULL
 };
 
-static picture_t *Filter( filter_t *, picture_t * );
-static int Mouse( filter_t *, vlc_mouse_t *, const vlc_mouse_t *, const
vlc_mouse_t * );
+typedef struct {
+        float f_x, f_y;
+ } point_t;
 
-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 * );
+typedef struct {
+    int32_t i_preview_size_x, i_preview_size_y;
 
-struct filter_sys_t
-{
-    /* */
-    int i_cols;
-    int i_rows;
+    int32_t i_border_size_x, i_border_size_y;
+    int32_t i_pieces_max_x, i_pieces_max_y;
+
+    int32_t i_lines, i_pitch;
+    int32_t i_visible_lines, i_visible_pitch;
+} puzzle_plane_t;
+
+typedef struct {
+    int32_t i_x, i_y;
+    int32_t i_size_x, i_size_y;
+} puzzle_array_t;
+
+typedef struct {
+    uint8_t i_type;  // 0 = fill ; 1 = offset
+    int32_t i_width;
+} row_section_t;
+
+typedef struct {
+    int32_t i_section_nbr;
+    row_section_t *ps_row_section;
+} piece_shape_row_t;
+
+typedef struct {
+    int32_t i_row_nbr;
+    int32_t i_first_row_offset;
+    piece_shape_row_t *ps_piece_shape_row;
+} piece_shape_t;
+
+typedef struct {
+    int32_t i_original_x, i_original_y;
+    int32_t i_actual_x, i_actual_y;
+    int32_t i_size_x, i_size_y;
+} piece_in_plane_t;
+
+typedef struct {
+    int32_t i_original_row, i_original_col;
+
+    int32_t i_top_shape, i_btm_shape, i_right_shape, i_left_shape;
+
+    piece_in_plane_t *ps_piece_in_plane;
+
+    int32_t i_actual_mirror; // +1 = without mirror ; -1 = with mirror
+    int8_t i_actual_angle; // 0 = 0°, 1 = 90°... rotation center = top-left
corner
+    int32_t i_step_x_x, i_step_x_y, i_step_y_y, i_step_y_x;
+    int32_t i_ORx, i_OTy, i_OLx, i_OBy; // location of original piece's
edges
+    int32_t i_TLx, i_TLy, i_TRx, i_TRy, i_BLx, i_BLy, i_BRx, i_BRy; //
location of grabed piece's corners
+    int32_t i_max_x, i_min_x, i_max_y, i_min_y, i_center_x, i_center_y;
+
+    bool b_finished;
+    bool b_overlap;
+
+    int32_t i_group_ID;
+} piece_t;
+
+typedef struct {
+    int32_t i_rows, i_cols;
+    int32_t i_pict_width, i_pict_height;
+    int32_t i_desk_width, i_desk_height;
+    uint8_t i_planes;
+    int32_t i_piece_types;
+    uint32_t i_pieces_nbr;
+    bool    b_preview;
+    int32_t i_preview_size;
+    int32_t i_shape_size;
+    int32_t i_border;
+    // game settings
+    int32_t i_auto_shuffle_speed, i_auto_solve_speed;
     bool b_blackslot;
-    int *pi_order;
-    int i_selected;
+    bool b_near;
+    bool b_advanced;
+    uint8_t i_rotate; // 0=none, 1=0/180, 2=0/90/180/270, 3=0/90/180/270 w/
mirror
+} param_t;
+
+struct filter_sys_t {
+    bool b_init;
+    bool b_bake_request;
+    bool b_shape_init;
+    param_t s_allocated;
+    param_t s_current_param;
+    param_t s_new_param;
+    bool    b_change_param;
+
     bool b_finished;
+    uint32_t i_done_count, i_tmp_done_count;
 
-    /* */
-    struct
-    {
-        atomic_flag b_uptodate;
-        atomic_bool b_blackslot;
-        atomic_uint i_cols;
-        atomic_uint i_rows;
-    } change;
+    bool b_shuffleRqst;
+    bool b_mouse_drag;
+    bool b_mouse_mvt;
+    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;
 };
 
+static picture_t *Filter( filter_t *, picture_t * );
+static int PuzzleCallback( vlc_object_t *, char const *, vlc_value_t,
vlc_value_t, void * );
+static int Mouse( filter_t *, vlc_mouse_t *, const vlc_mouse_t *, const
vlc_mouse_t * );
+
+static int bake_puzzle ( filter_t *, picture_t * , picture_t * );
+static int bake_puzzle_array ( filter_t *, picture_t * , picture_t * );
+static void free_ps_puzzle_array ( filter_t * );
+static int bake_piece ( filter_t * );
+static void free_ps_pieces ( filter_t * );
+static int bake_pieces_shapes ( filter_t * );
+static void free_ps_pieces_shapes ( filter_t * );
+
+static bool IsValid( filter_sys_t *p_sys, int32_t *pi_pce_lst );
+static void Shuffle( filter_t * );
+static void generate_rand_pce_list( filter_t *p_filter, int32_t
**pi_pce_lst );
+static bool IsFinished( filter_sys_t *, int32_t *pi_pce_lst );
+static int find_piece( filter_t *p_filter, int32_t i_x, int32_t i_y,
int32_t i_except);
+static void calculate_corners( filter_t *,  int32_t i_piece );
+static void piece_foreground( filter_t *p_filter, int32_t i_piece);
+static void count_pce_group( filter_t *p_filter);
+static void solve_pces_group( filter_t *p_filter);
+static void solve_pces_accuracy( filter_t *p_filter);
+static void sort_layers( filter_t *p_filter);
+static void rotate_pce( filter_t *p_filter, int32_t i_piece, int8_t
i_rotate_mirror, int32_t i_center_x, int32_t i_center_y, bool b_avoid_mirror
);
+static void move_group( filter_t *p_filter, int32_t i_piece, int32_t i_dx,
int32_t i_dy);
+
+static void auto_solve( filter_t *p_filter);
+static void auto_shuffle( filter_t *p_filter);
+
+static void puzzle_preset_background(picture_t *p_pic_dst, uint8_t Y,
uint8_t U, uint8_t V);
+static void puzzle_draw_borders( filter_t *p_filter, picture_t *p_pic,
picture_t *p_pic_dst);
+static void puzzle_draw_preview( filter_t *p_filter, picture_t *p_pic,
picture_t *p_pic_dst);
+static void puzzle_draw_pieces( filter_t *p_filter, picture_t *p_pic,
picture_t *p_pic_dst);
+static void draw_sign(picture_t *p_pic_dst, int32_t i_x, int32_t i_y,
int32_t i_size_x, int32_t i_size_y, const char **ppsz_sign, bool b_reverse);
+static void draw_rectangle(picture_t *p_pic_dst, int32_t x, int32_t y,
int32_t i_w, int32_t i_h, uint8_t Y, uint8_t U, uint8_t V );
+static void fill_rectangle(picture_t *p_pic_dst, int32_t x, int32_t y,
int32_t i_w, int32_t i_h, uint8_t Y, uint8_t U, uint8_t V );
+
+static int32_t diagonal_limit( filter_t *p_filter, int32_t i_y, bool
b_left, uint8_t i_plane );
+
+static point_t *scale_curve_H(int32_t i_size_x, int32_t i_size_y, uint8_t
i_pts_nbr, point_t *ps_pt, int32_t i_shape_size);
+static point_t *H_2_scale_curve_V(int32_t i_size_x, int32_t i_size_y,
uint8_t i_pts_nbr, point_t *ps_pt, int32_t i_shape_size);
+static point_t *curve_H_2_V(uint8_t i_pts_nbr, point_t *ps_pt);
+static point_t *curve_H_2_negative(uint8_t i_pts_nbr, point_t *ps_pt);
+static point_t *curve_V_2_negative(uint8_t i_pts_nbr, point_t *ps_pt);
+static point_t *rand_bezier(uint8_t i_pts_nbr);
+static void generate_sectTopB( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_plane);
+static void generate_sectLeftB( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_plane);
+static void generate_sectRightB( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_plane);
+static void generate_sectBtmB( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_plane);
+static void generate_sectTop( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_pts_nbr, point_t *ps_pt, uint8_t i_plane);
+static void generate_sectLeft( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_pts_nbr, point_t *ps_pt, uint8_t i_plane);
+static void generate_sectLeft2Right( filter_t *p_filter, piece_shape_t
*ps_piece_shape, piece_shape_t *ps_left_piece_shape, uint8_t i_plane);
+static void generate_sectTop2Btm( filter_t *p_filter, piece_shape_t
*ps_piece_shape, piece_shape_t *ps_top_piece_shape, uint8_t i_plane);
+
+static void save(filter_t *p_filter);
+static void load( filter_t *p_filter);
+
 #define SHUFFLE_WIDTH 81
 #define SHUFFLE_HEIGHT 13
-static const char *shuffle_button[] =
-{
-"..........................................................................
.......",
-"..............  ............................   ........   ......
...............",
-"..............  ...........................  .........  ........
...............",
-"..............  ...........................  .........  ........
...............",
-"..     .......  .    .......  ....  ......     ......     ......  ........
...",
-".  .... ......   ...  ......  ....  .......  .........  ........  .......
..  ..",
-".  ...........  ....  ......  ....  .......  .........  ........  ......
....  .",
-".      .......  ....  ......  ....  .......  .........  ........  ......
.",
-"..      ......  ....  ......  ....  .......  .........  ........  ......
.......",
-"......  ......  ....  ......  ....  .......  .........  ........  ......
.......",
-". ....  ......  ....  ......  ...   .......  .........  ........  .......
.... .",
-"..     .......  ....  .......    .  .......  .........  ........  ........
..",
-"..........................................................................
......."
+static const char *ppsz_shuffle_button[] =
+{
+"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
ooooooo",
+"oooooooooooooo  oooooooooooooooooooooooooooo   oooooooo   oooooo
ooooooooooooooo",
+"oooooooooooooo  ooooooooooooooooooooooooooo  ooooooooo  oooooooo
ooooooooooooooo",
+"oooooooooooooo  ooooooooooooooooooooooooooo  ooooooooo  oooooooo
ooooooooooooooo",
+"oo     ooooooo  o    ooooooo  oooo  oooooo     oooooo     oooooo  oooooooo
ooo",
+"o  oooo oooooo   ooo  oooooo  oooo  ooooooo  ooooooooo  oooooooo  ooooooo
oo  oo",
+"o  ooooooooooo  oooo  oooooo  oooo  ooooooo  ooooooooo  oooooooo  oooooo
oooo  o",
+"o      ooooooo  oooo  oooooo  oooo  ooooooo  ooooooooo  oooooooo  oooooo
o",
+"oo      oooooo  oooo  oooooo  oooo  ooooooo  ooooooooo  oooooooo  oooooo
ooooooo",
+"oooooo  oooooo  oooo  oooooo  oooo  ooooooo  ooooooooo  oooooooo  oooooo
ooooooo",
+"o oooo  oooooo  oooo  oooooo  ooo   ooooooo  ooooooooo  oooooooo  ooooooo
oooo o",
+"oo     ooooooo  oooo  ooooooo    o  ooooooo  ooooooooo  oooooooo  oooooooo
oo",
+"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo
ooooooo"
+};
+
+#define ARROW_WIDTH 13
+#define ARROW_HEIGHT 13
+static const char *ppsz_rot_arrow_sign[] =
+{
+"    .ooo.    ",
+"   .o. .oo.  ",
+"  .o.    .o. ",
+" .o.      .o.",
+" o.        .o",
+".o          .",
+".o   .       ",
+" o. .o.      ",
+" .o..o.      ",
+"  o..o       ",
+"   .o.       ",
+"ooooo.       ",
+"  ..         "
 };
 
+static const char *ppsz_mir_arrow_sign[] =
+{
+"             ",
+"             ",
+"    .   .    ",
+"  .o.   .o.  ",
+" .o.     .o. ",
+".o.       .o.",
+"ooooooooooooo",
+".o.       .o.",
+" .o.     .o. ",
+"  .o.   .o.  ",
+"    .   .    ",
+"             ",
+"             "
+};
 
 /**
  * Open the filter
@@ -148,23 +392,76 @@ static int Open( vlc_object_t *p_this )
     config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
                        p_filter->p_cfg );
 
+    p_sys->b_init = false;
+    p_sys->b_shuffleRqst = true;
+    p_sys->b_change_param = true;
+    p_sys->b_shape_init = false;
     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_shapes = NULL;
+    p_sys->ps_pieces = NULL;
+    p_sys->ps_pieces_tmp = NULL;
+    p_sys->pi_group_qty = NULL;
+    p_sys->b_mouse_drag = false;
+    p_sys->b_mouse_mvt = false;
+    p_sys->i_mouse_drag_pce = -1;
+    p_sys->i_pointed_pce = -1;
+    p_sys->i_magnet_accuracy = 3;
+    p_sys->i_mouse_x = 0;
+    p_sys->i_mouse_y = 0;
+
+    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.b_blackslot =
+        var_CreateGetBoolCommand( p_filter, CFG_PREFIX "black-slot" );
+    p_sys->s_new_param.b_near =
+        var_CreateGetBoolCommand( p_filter, CFG_PREFIX "near" );
+    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.b_advanced =
+        var_CreateGetBoolCommand( p_filter, CFG_PREFIX "advanced-game" );
+    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" );
 
-    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;
+    p_sys->i_preview_pos = 0;// 0=top-left, top-right, bottom right,
bottom-left
 
     var_AddCallback( p_filter, CFG_PREFIX "rows", PuzzleCallback, p_sys );
     var_AddCallback( p_filter, CFG_PREFIX "cols", PuzzleCallback, p_sys );
     var_AddCallback( p_filter, CFG_PREFIX "black-slot", PuzzleCallback,
p_sys );
+    var_AddCallback( p_filter, CFG_PREFIX "near", PuzzleCallback, p_sys );
+    var_AddCallback( p_filter, CFG_PREFIX "border", PuzzleCallback, p_sys
);
+    var_AddCallback( p_filter, CFG_PREFIX "preview", PuzzleCallback, p_sys
);
+    var_AddCallback( p_filter, CFG_PREFIX "preview-size", PuzzleCallback,
p_sys );
+    var_AddCallback( p_filter, CFG_PREFIX "shape-size", PuzzleCallback,
p_sys );
+    var_AddCallback( p_filter, CFG_PREFIX "advanced-game", PuzzleCallback,
p_sys );
+    var_AddCallback( p_filter, CFG_PREFIX "auto-shuffle", PuzzleCallback,
p_sys );
+    var_AddCallback( p_filter, CFG_PREFIX "auto-solve", PuzzleCallback,
p_sys );
+    var_AddCallback( p_filter, CFG_PREFIX "rotation", PuzzleCallback, p_sys
);
 
     p_filter->pf_video_filter = Filter;
     p_filter->pf_video_mouse = Mouse;
 
+    p_sys->ps_bezier_pts_H = malloc( sizeof( point_t *) * SHAPES_QTY );
+    for (int32_t i_shape = 0; i_shape<SHAPES_QTY; i_shape++)
+        p_sys->ps_bezier_pts_H[i_shape] = rand_bezier(7);
+
     return VLC_SUCCESS;
 }
 
@@ -179,8 +476,32 @@ static void Close( vlc_object_t *p_this )
     var_DelCallback( p_filter, CFG_PREFIX "rows", PuzzleCallback, p_sys );
     var_DelCallback( p_filter, CFG_PREFIX "cols", PuzzleCallback, p_sys );
     var_DelCallback( p_filter, CFG_PREFIX "black-slot", PuzzleCallback,
p_sys );
+    var_DelCallback( p_filter, CFG_PREFIX "near", PuzzleCallback, p_sys );
+    var_DelCallback( p_filter, CFG_PREFIX "border", PuzzleCallback, p_sys
);
+    var_DelCallback( p_filter, CFG_PREFIX "preview", PuzzleCallback, p_sys
);
+    var_DelCallback( p_filter, CFG_PREFIX "preview-size", PuzzleCallback,
p_sys );
+    var_DelCallback( p_filter, CFG_PREFIX "shape-size", PuzzleCallback,
p_sys );
+    var_DelCallback( p_filter, CFG_PREFIX "advanced-game", PuzzleCallback,
p_sys );
+    var_DelCallback( p_filter, CFG_PREFIX "auto-shuffle", PuzzleCallback,
p_sys );
+    var_DelCallback( p_filter, CFG_PREFIX "auto-solve", PuzzleCallback,
p_sys );
+    var_DelCallback( p_filter, CFG_PREFIX "rotation", PuzzleCallback, p_sys
);
+
+    vlc_mutex_destroy( &p_sys->lock );
+    vlc_mutex_destroy( &p_sys->pce_lock );
 
-    free( p_sys->pi_order );
+    free_ps_puzzle_array ( p_filter );
+    free_ps_pieces_shapes ( p_filter);
+    free_ps_pieces ( p_filter );
+    if (p_sys->ps_desk_planes != NULL)
+        free(p_sys->ps_desk_planes);
+    if (p_sys->ps_pict_planes != NULL)
+        free(p_sys->ps_pict_planes);
+    if (p_sys->pi_order != NULL )
+        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 );
 }
@@ -190,158 +511,266 @@ static void Close( vlc_object_t *p_this )
  */
 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
 {
+    const video_format_t  *p_fmt = &p_filter->fmt_in.video;
     filter_sys_t *p_sys = p_filter->p_sys;
 
-    picture_t *p_outpic = filter_NewPicture( p_filter );
-    if( !p_outpic )
+    int ret = 0;
+    p_sys->b_bake_request = false;
+
+    if( !p_pic ) return NULL;
+
+    if( (p_filter->fmt_in.video.i_height == 0) ||
+        (p_filter->fmt_in.video.i_width == 0) )
+        return NULL;
+
+    if( (p_filter->fmt_out.video.i_height == 0) ||
+        (p_filter->fmt_out.video.i_width == 0) )
+        return NULL;
+
+    picture_t *p_pic_dst = filter_NewPicture( p_filter );
+    if( !p_pic_dst )
     {
         picture_Release( p_pic );
         return NULL;
     }
 
-    /* */
-    if( !atomic_flag_test_and_set( &p_sys->change.b_uptodate ) )
-    {
-        p_sys->i_rows      = atomic_load( &p_sys->change.i_rows );
-        p_sys->i_cols      = atomic_load( &p_sys->change.i_cols );
-        p_sys->b_blackslot = atomic_load( &p_sys->change.b_blackslot );
-        Shuffle( p_sys );
-    }
+    //     tailles des planes, positions et tailles des pieces dans l'image
d'origine, positions aciuelles des pieces
+    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;
 
-    /* */
-    const int i_rows = p_sys->i_rows;
-    const int i_cols = p_sys->i_cols;
+    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;
 
-    /* Draw each piece of the puzzle at the right place */
-    for( int i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
-    {
-        const plane_t *p_in = &p_pic->p[i_plane];
-        plane_t *p_out = &p_outpic->p[i_plane];
+    if ( p_sys->s_allocated.i_planes != p_pic_dst->i_planes)
+        p_sys->b_init = false;
 
-        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;
+    p_sys->s_current_param.i_planes = p_pic_dst->i_planes;
 
-            int i_col = (i % i_cols) * i_piece_width;
-            int i_row = (i / i_cols) * i_piece_height;
-            int i_last_row = i_row + i_piece_height;
+    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_dst->p[i_plane].i_lines)
+                    || (p_sys->ps_pict_planes[i_plane].i_pitch !=
p_pic_dst->p[i_plane].i_pitch)
+                    || (p_sys->ps_pict_planes[i_plane].i_visible_lines !=
p_pic_dst->p[i_plane].i_visible_lines)
+                    ||(p_sys->ps_pict_planes[i_plane].i_visible_pitch !=
p_pic_dst->p[i_plane].i_visible_pitch) )
+                p_sys->b_init = false;
+        }
+    }
 
-            int i_ocol = (p_sys->pi_order[i] % i_cols) * i_piece_width;
-            int i_orow = (p_sys->pi_order[i] / i_cols) * i_piece_height;
+    p_sys->s_current_param.i_pict_width = (int) p_fmt->i_width;
+    p_sys->s_current_param.i_pict_height = (int) p_fmt->i_height;
+    p_sys->s_current_param.i_desk_width = (int)
p_pic_dst->p[0].i_visible_pitch;
+    p_sys->s_current_param.i_desk_height = (int)
p_pic_dst->p[0].i_visible_lines;
 
-            if( p_sys->b_blackslot && !p_sys->b_finished && i ==
p_sys->i_selected )
-            {
-                uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
-                for( int r = i_row; r < i_last_row; r++ )
-                {
-                    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 );
-                }
-            }
+    vlc_mutex_lock( &p_sys->lock );
 
-            /* Draw the borders of the selected slot */
-            if( i_plane == 0 && !p_sys->b_blackslot && p_sys->i_selected ==
i )
-            {
-                memset( p_out->p_pixels + i_row * p_out->i_pitch + i_col,
-                        0xff, i_piece_width );
-                for( int r = i_row; r < i_last_row; r++ )
-                {
-                    p_out->p_pixels[r * p_out->i_pitch + i_col + 0
+ 0 ] = 0xff;
-                    p_out->p_pixels[r * p_out->i_pitch + i_col +
i_piece_width - 1 ] = 0xff;
-                }
-                memset( p_out->p_pixels + (i_last_row - 1) * p_out->i_pitch
+ i_col,
-                        0xff, i_piece_width );
-            }
+    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.b_advanced !=
p_sys->s_new_param.b_advanced
+                || p_sys->s_allocated.i_rotate !=
p_sys->s_new_param.i_rotate
+                || p_sys->b_bake_request  || !p_sys->b_init )
+        {
+            p_sys->b_bake_request = true;
+            p_sys->b_init = false;
+            p_sys->b_shuffleRqst = true;
+            p_sys->b_shape_init = false;
         }
-    }
 
-    /* Draw the 'Shuffle' button if the puzzle is finished */
-    if( p_sys->b_finished )
-    {
-        plane_t *p_out = &p_outpic->p[Y_PLANE];
-        for( int i = 0; i < SHUFFLE_HEIGHT; i++ )
+        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 )
         {
-            for( int j = 0; j < SHUFFLE_WIDTH; j++ )
-            {
-                if( shuffle_button[i][j] == '.' )
-                   p_out->p_pixels[ i * p_out->i_pitch + j ] = 0xff;
-            }
+            p_sys->b_bake_request = true;
+            p_sys->b_shape_init = false;
         }
-    }
 
-    return CopyInfoAndRelease( p_outpic, p_pic );
-}
+        if ( p_sys->s_current_param.b_blackslot !=
p_sys->s_new_param.b_blackslot
+                && p_sys->i_selected == -1
+                && p_sys->s_current_param.b_blackslot )
+            p_sys->i_selected = 0;
 
-static int Mouse( filter_t *p_filter, vlc_mouse_t *p_mouse,
-                  const vlc_mouse_t *p_old, const vlc_mouse_t *p_new )
-{
-    filter_sys_t *p_sys = p_filter->p_sys;
-    const video_format_t  *p_fmt = &p_filter->fmt_in.video;
+        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);
 
-    /* Only take events inside the puzzle erea */
-    if( p_new->i_x < 0 || p_new->i_x >= (int)p_fmt->i_width ||
-        p_new->i_y < 0 || p_new->i_y >= (int)p_fmt->i_height )
-        return VLC_EGENERIC;
+        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);
 
-    /* */
-    const bool b_clicked = vlc_mouse_HasPressed( p_old, p_new,
MOUSE_BUTTON_LEFT );
+        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;
+    }
 
-    /* If the puzzle is finished, shuffle it if needed */
-    if( p_sys->b_finished )
+    vlc_mutex_unlock( &p_sys->lock );
+
+    // preset output pic:
+    if ( !p_sys->b_bake_request && !p_sys->b_shuffleRqst && p_sys->b_init
&& !p_sys->b_finished )
+        puzzle_preset_background(p_pic_dst, 0, 127, 127);
+    else
     {
-        if( b_clicked &&
-            p_new->i_x < SHUFFLE_WIDTH && p_new->i_y < SHUFFLE_HEIGHT )
+        // copy src to dst during init & bake process
+        for( uint8_t i_plane = 0; i_plane < p_pic_dst->i_planes; i_plane++
)
+            memcpy( p_pic_dst->p[i_plane].p_pixels,
p_pic->p[i_plane].p_pixels,
+                p_pic->p[i_plane].i_pitch * (int32_t)
p_pic->p[i_plane].i_visible_lines );
+    }
+
+    // bake initial puzzle data & shapes
+    if ( p_sys->b_bake_request )
+    {
+        if (!p_sys->b_shuffleRqst)
         {
-            atomic_flag_clear( &p_sys->change.b_uptodate );
-            return VLC_EGENERIC;
+            save(p_filter);
+            bake_puzzle( p_filter, p_pic_dst, p_pic );
+            load( p_filter);
         }
         else
         {
-            /* This is the only case where we can forward the mouse */
-            *p_mouse = *p_new;
-            return VLC_SUCCESS;
+            ret = bake_puzzle( p_filter, p_pic_dst, p_pic );
+            if ( ret !=0 )
+                return CopyInfoAndRelease( p_pic_dst, p_pic );
         }
     }
-    if( !b_clicked )
-        return VLC_EGENERIC;
 
-    /* */
-    const int i_pos_x = p_new->i_x * p_sys->i_cols / p_fmt->i_width;
-    const int i_pos_y = p_new->i_y * p_sys->i_rows / p_fmt->i_height;
-    const int i_pos = i_pos_y * p_sys->i_cols + i_pos_x;
+    // shuffle the desk and generate data
+    if ( p_sys->b_shuffleRqst && p_sys->b_init )
+        bake_piece ( p_filter );
 
-    if( p_sys->i_selected == -1 )
-    {
-        p_sys->i_selected = i_pos;
+    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++)
+        solve_pces_accuracy( p_filter );
+    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++)
+        solve_pces_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 )
+        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 )
+        sort_layers( p_filter);
+    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;
+        calculate_corners( p_filter, p_sys->i_calc_corn_loop );
     }
-    else if( p_sys->i_selected == i_pos && !p_sys->b_blackslot )
+
+    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;
+        // computer moves some piece:
+        auto_shuffle( p_filter );
+        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 )
+
+    vlc_mutex_unlock( &p_sys->pce_lock );
+
+    if ( !p_sys->b_bake_request && p_sys->b_init  && p_sys->ps_puzzle_array
!= NULL )
     {
-        /* 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;
+        // generate output pic:
+        puzzle_draw_borders(p_filter, p_pic, p_pic_dst);
+
+        p_sys->i_pointed_pce = -1;
+        puzzle_draw_pieces(p_filter, p_pic, p_pic_dst);
+
+        if (p_sys->i_pointed_pce == -1)
+            p_sys->i_mouse_drag_pce = 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, p_pic_dst);
+
+        // highlight the selected piece:
+        if ( p_sys->i_selected != -1 && !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);
+
+            draw_rectangle(p_pic_dst,
+                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_size_x,
+                p_sys->ps_puzzle_array[r][c][0].i_size_y,
+                255, 127, 127);
+        }
+
+        if ( p_sys->i_selected != -1 && 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);
+
+            fill_rectangle(p_pic_dst,
+                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_size_x,
+                p_sys->ps_puzzle_array[r][c][0].i_size_y,
+                0, 127, 127);
+        }
+
+        /* Draw the 'Shuffle' button if the puzzle is finished */
+        if ( p_sys->b_finished )
+            draw_sign(p_pic_dst, 0, 0, SHUFFLE_WIDTH, SHUFFLE_HEIGHT,
ppsz_shuffle_button, false);
+
+        // draw an arrow to indicate rotation
+        if ((p_sys->i_mouse_drag_pce != -1) && !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_pieces_max_x / 6;
+            else
+                i_delta_x = p_sys->ps_desk_planes[0].i_pieces_max_y / 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 )
+                draw_sign(p_pic_dst, p_sys->i_mouse_x - ARROW_WIDTH,
p_sys->i_mouse_y, ARROW_WIDTH, ARROW_HEIGHT, ppsz_rot_arrow_sign, false);
+            else if ( p_sys->i_mouse_action == -1 )
+                draw_sign(p_pic_dst, p_sys->i_mouse_x - ARROW_WIDTH,
p_sys->i_mouse_y, ARROW_WIDTH, ARROW_HEIGHT, ppsz_rot_arrow_sign, true);
+            else if ( p_sys->i_mouse_action == 4 )
+                draw_sign(p_pic_dst, p_sys->i_mouse_x - ARROW_WIDTH,
p_sys->i_mouse_y, ARROW_WIDTH, ARROW_HEIGHT, ppsz_mir_arrow_sign, false);
+
+            vlc_mutex_unlock( &p_sys->pce_lock );
+        }
 
-        p_sys->i_selected = p_sys->b_blackslot ? i_pos : -1;
-        p_sys->b_finished = IsFinished( p_sys );
     }
-    return VLC_EGENERIC;
+
+    return CopyInfoAndRelease( p_pic_dst, p_pic );
 }
 
 
/***************************************************************************
**
@@ -352,90 +781,2756 @@ static int PuzzleCallback( vlc_object_t *p_this,
char const *psz_var,
                            void *p_data )
 {
     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" ) )
-        atomic_store( &p_sys->change.i_rows, __MAX( 2, newval.i_int ) );
+    {
+        p_sys->s_new_param.i_rows = __MAX( 1, newval.i_int );
+    }
     else if( !strcmp( psz_var, CFG_PREFIX "cols" ) )
-        atomic_store( &p_sys->change.i_cols, __MAX( 2, newval.i_int ) );
+    {
+        p_sys->s_new_param.i_cols = __MAX( 1, 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 );
+    {
+        p_sys->s_new_param.b_blackslot = newval.b_bool;
+    }
+    else if( !strcmp( psz_var, CFG_PREFIX "near" ) )
+    {
+        p_sys->s_new_param.b_near = newval.b_bool;
+    }
+    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 "advanced-game" ) )
+    {
+        p_sys->s_new_param.b_advanced = newval.b_bool;
+    }
+    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;
+    }
+
+    p_sys->b_change_param = true;
+    vlc_mutex_unlock( &p_sys->lock );
 
     return VLC_SUCCESS;
 }
 
-static bool IsFinished( filter_sys_t *p_sys )
+static int 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 = &p_filter->fmt_in.video;
+
+    /* Only take events inside the puzzle erea */
+    if( p_new->i_x < 0 || p_new->i_x >= (int)p_fmt->i_width ||
+        p_new->i_y < 0 || p_new->i_y >= (int)p_fmt->i_height )
+        return VLC_EGENERIC;
+
+    if (! p_sys->b_init || p_sys->b_change_param)
     {
-        if( i != p_sys->pi_order[i] )
-            return false;
+        *p_mouse = *p_new;
+        return VLC_SUCCESS;
     }
-    return true;
-}
-
-static bool IsValid( filter_sys_t *p_sys )
-{
-    const int i_count = p_sys->i_cols * p_sys->i_rows;
 
-    if( !p_sys->b_blackslot )
-        return true;
+    p_sys->i_mouse_x = p_new->i_x;
+    p_sys->i_mouse_y = p_new->i_y;
 
-    int d = 0;
-    for( int i = 0; i < i_count; i++ )
+    /* If the puzzle is finished, shuffle it if needed */
+    if( p_sys->b_finished )
     {
-        if( p_sys->pi_order[i] == i_count - 1 )
+        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_HEIGHT )
         {
-            d += i / p_sys->i_cols + 1;
-            continue;
+            p_sys->b_shuffleRqst = true;
+            return VLC_EGENERIC;
         }
-        for( int j = i+1; j < i_count; j++ )
+        else
         {
-            if( p_sys->pi_order[j] == i_count - 1 )
-                continue;
-            if( p_sys->pi_order[i] > p_sys->pi_order[j] )
-                d++;
+            /* otherwise we can forward the mouse */
+            *p_mouse = *p_new;
+            return VLC_SUCCESS;
         }
     }
-    return (d%2) == 0;
-}
 
-static void Shuffle( filter_sys_t *p_sys )
-{
-    const unsigned i_count = p_sys->i_cols * p_sys->i_rows;
+    if ( !p_sys->s_current_param.b_advanced )
+    {
+        const bool b_clicked = vlc_mouse_HasPressed( p_old, p_new,
MOUSE_BUTTON_LEFT );
+
+        if( b_clicked )
+        {
+            /* */
+            const int32_t i_border_size_x = p_fmt->i_width *
p_sys->s_current_param.i_border / 100 / 2;
+            const int32_t i_border_size_y = p_fmt->i_height *
p_sys->s_current_param.i_border / 100 / 2;
+            const int32_t i_pos_x = (p_new->i_x - i_border_size_x) *
p_sys->s_allocated.i_cols / (p_fmt->i_width - 2*i_border_size_x);
+            const int32_t i_pos_y = (p_new->i_y - i_border_size_y) *
p_sys->s_allocated.i_rows / (p_fmt->i_height - 2*i_border_size_y);
 
-    free( p_sys->pi_order );
+            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
+            // do not take into account if border clicked
+            if ((p_new->i_x <= i_border_size_x) || (p_new->i_y <=
i_border_size_y) || (p_new->i_x >= (int) p_fmt->i_width -  i_border_size_x)
|| (p_new->i_y >= (int) p_fmt->i_height -  i_border_size_y ) )
+            {
+                //RAS (border clicked)
+            }
+            else if( p_sys->i_selected == -1 )
+            {
+                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_size_x =
p_sys->ps_puzzle_array[row][col][i_plane].i_size_x;
+
p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_size_y =
p_sys->ps_puzzle_array[row][col][i_plane].i_size_y;
+
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 : -1;
+                p_sys->b_finished = IsFinished( p_sys, p_sys->pi_order );
+            }
+        }
+    }
+    else //if (p_sys->s_current_param.b_advanced)
     {
-        for( unsigned i = 0; i < i_count; i++ )
-            p_sys->pi_order[i] = -1;
+        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;
+        }
 
-        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 )
-                p_sys->pi_order[i] = c++;
-        }
-        p_sys->b_finished = IsFinished( p_sys );
 
-    } while( p_sys->b_finished || !IsValid( p_sys ) );
+            vlc_mutex_lock( &p_sys->pce_lock );
 
-    if( p_sys->b_blackslot )
-    {
-        for( unsigned i = 0; i < i_count; i++ )
+            if (p_sys->i_mouse_drag_pce != -1)
+            {
+                piece_foreground( p_filter, p_sys->i_mouse_drag_pce);
+                p_sys->i_mouse_drag_pce = 0;
+
+                int32_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 )
+                    {
+                        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 );
+
+        }
+        else if( vlc_mouse_HasReleased( p_old, p_new, MOUSE_BUTTON_LEFT ) )
         {
-            if( p_sys->pi_order[i] == (int)i_count - 1 )
+            if ( !p_sys->b_mouse_mvt && p_sys->b_mouse_drag )
             {
-                p_sys->i_selected = i;
-                break;
+                // piece clicked without any mvt => rotate it or mirror
+                if ( p_sys->s_current_param.i_rotate != 0)
+                {
+                    vlc_mutex_lock( &p_sys->pce_lock );
+
+                    int32_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 )
+                            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
+        {
+            // 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->i_width / 2 && p_new->i_y <
(int)p_fmt->i_height / 2 )
+                    p_sys->i_preview_pos++;
+                break;
+              case 1:
+                if ( p_new->i_x > (int)p_fmt->i_width / 2 && p_new->i_y <
(int)p_fmt->i_height / 2 )
+                    p_sys->i_preview_pos++;
+                break;
+              case 2:
+                if ( p_new->i_x > (int)p_fmt->i_width / 2 && p_new->i_y >
(int)p_fmt->i_height / 2 )
+                    p_sys->i_preview_pos++;
+                break;
+              case 3:
+                if ( p_new->i_x < (int)p_fmt->i_width / 2 && p_new->i_y >
(int)p_fmt->i_height / 2 )
+                    p_sys->i_preview_pos++;
+                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->i_width ) || ( p_new->i_y >= (int)
p_fmt->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 );
+
+                    move_group( p_filter, p_sys->i_mouse_drag_pce, i_dx,
i_dy);
+
+                    vlc_mutex_unlock( &p_sys->pce_lock );
+                }
+            }
+        }
+    }
+    return VLC_EGENERIC;
+}
+
+static int bake_puzzle( filter_t *p_filter, picture_t *p_pic_dst, picture_t
*p_pic_in)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+    int ret = 0;
+
+    free_ps_puzzle_array ( p_filter );
+    free_ps_pieces_shapes ( p_filter);
+    free_ps_pieces ( p_filter );
+
+    p_sys->s_allocated.i_rows = p_sys->s_current_param.i_rows;
+    p_sys->s_allocated.i_cols = p_sys->s_current_param.i_cols;
+    p_sys->s_allocated.i_planes = p_sys->s_current_param.i_planes;
+    if (p_sys->s_current_param.b_advanced) {
+        p_sys->s_allocated.i_piece_types = PIECE_TYPE_NBR;
+    } else {
+        p_sys->s_allocated.i_piece_types = 0;
+    }
+    p_sys->s_allocated.i_pieces_nbr = p_sys->s_allocated.i_rows *
p_sys->s_allocated.i_cols;
+    p_sys->s_allocated.b_preview = p_sys->s_current_param.b_preview;
+    p_sys->s_allocated.i_preview_size =
p_sys->s_current_param.i_preview_size;
+    p_sys->s_allocated.i_border = p_sys->s_current_param.i_border;
+    p_sys->s_allocated.b_blackslot = p_sys->s_current_param.b_blackslot;
+    p_sys->s_allocated.b_near = p_sys->s_current_param.b_near;
+    p_sys->s_allocated.i_shape_size = p_sys->s_current_param.i_shape_size;
+    p_sys->s_allocated.b_advanced = p_sys->s_current_param.b_advanced;
+    p_sys->s_allocated.i_auto_shuffle_speed =
p_sys->s_current_param.i_auto_shuffle_speed;
+    p_sys->s_allocated.i_auto_solve_speed =
p_sys->s_current_param.i_auto_solve_speed;
+    p_sys->s_allocated.i_rotate = p_sys->s_current_param.i_rotate;
+
+    ret = bake_puzzle_array ( p_filter, p_pic_dst, p_pic_in );
+    if (ret != 0)
+        return ret;
+
+    if (p_sys->s_current_param.b_advanced &&
p_sys->s_allocated.i_shape_size != 0)
+    {
+        ret = bake_pieces_shapes ( p_filter );
+        if (ret != 0)
+            return ret;
+    }
+
+    ret = bake_piece ( p_filter );
+    if (ret != 0)
+        return ret;
+
+    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 = true;
+
+    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;
+
+    return 0;
+}
+
+static int bake_puzzle_array( filter_t *p_filter, picture_t *p_pic_dst,
picture_t *p_pic_in)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    free_ps_puzzle_array(p_filter);
+
+    p_sys->ps_puzzle_array = malloc( sizeof( puzzle_array_t** ) *
(p_sys->s_allocated.i_rows + 1));
+    if( !p_sys->ps_puzzle_array )
+        return VLC_ENOMEM;
+
+    for (int32_t r=0; r < p_sys->s_allocated.i_rows + 1; r++)
+    {
+        p_sys->ps_puzzle_array[r] = malloc( sizeof( puzzle_array_t* ) *
(p_sys->s_allocated.i_cols + 1));
+        if( !p_sys->ps_puzzle_array[r] )
+            return VLC_ENOMEM;
+        for (int32_t c=0; c < p_sys->s_allocated.i_cols + 1; c++)
+        {
+            p_sys->ps_puzzle_array[r][c] = malloc( sizeof( puzzle_array_t )
* p_sys->s_allocated.i_planes);
+            if( !p_sys->ps_puzzle_array[r][c] )
+                return VLC_ENOMEM;
+        }
+    }
+
+    p_sys->ps_desk_planes = malloc( sizeof( puzzle_plane_t ) *
p_sys->s_allocated.i_planes);
+    if( !p_sys->ps_desk_planes )
+        return VLC_ENOMEM;
+    p_sys->ps_pict_planes = malloc( sizeof( puzzle_plane_t ) *
p_sys->s_allocated.i_planes);
+    if( !p_sys->ps_pict_planes )
+        return VLC_ENOMEM;
+
+    for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes;
i_plane++) {
+        p_sys->ps_desk_planes[i_plane].i_lines =
p_pic_dst->p[i_plane].i_lines;
+        p_sys->ps_desk_planes[i_plane].i_pitch =
p_pic_dst->p[i_plane].i_pitch;
+        p_sys->ps_desk_planes[i_plane].i_visible_lines =
p_pic_dst->p[i_plane].i_visible_lines;
+        p_sys->ps_desk_planes[i_plane].i_visible_pitch =
p_pic_dst->p[i_plane].i_visible_pitch;
+
+        p_sys->ps_desk_planes[i_plane].i_preview_size_x =
p_pic_dst->p[i_plane].i_visible_pitch *
p_sys->s_current_param.i_preview_size / 100;
+        p_sys->ps_desk_planes[i_plane].i_preview_size_y =
p_pic_dst->p[i_plane].i_visible_lines *
p_sys->s_current_param.i_preview_size / 100;
+
+        p_sys->ps_desk_planes[i_plane].i_border_size_x =
p_pic_dst->p[i_plane].i_visible_pitch * p_sys->s_current_param.i_border / 2
/ 100;
+        p_sys->ps_desk_planes[i_plane].i_border_size_y =
p_pic_dst->p[i_plane].i_visible_pitch * p_sys->s_current_param.i_border / 2
/ 100;
+
+        p_sys->ps_desk_planes[i_plane].i_pieces_max_x = ((
p_pic_dst->p[i_plane].i_visible_pitch
+                - 2 * p_sys->ps_desk_planes[i_plane].i_border_size_x ) +
p_sys->s_allocated.i_cols - 1 ) / p_sys->s_allocated.i_cols;
+        p_sys->ps_desk_planes[i_plane].i_pieces_max_y = ((
p_pic_dst->p[i_plane].i_visible_lines
+                - 2 * p_sys->ps_desk_planes[i_plane].i_border_size_y ) +
p_sys->s_allocated.i_rows - 1 ) / p_sys->s_allocated.i_rows;
+
+        p_sys->ps_pict_planes[i_plane].i_lines =
p_pic_in->p[i_plane].i_lines;
+        p_sys->ps_pict_planes[i_plane].i_pitch =
p_pic_in->p[i_plane].i_pitch;
+        p_sys->ps_pict_planes[i_plane].i_visible_lines =
p_pic_in->p[i_plane].i_visible_lines;
+        p_sys->ps_pict_planes[i_plane].i_visible_pitch =
p_pic_in->p[i_plane].i_visible_pitch;
+
+        p_sys->ps_pict_planes[i_plane].i_preview_size_x =
p_pic_in->p[i_plane].i_visible_pitch * p_sys->s_current_param.i_preview_size
/ 100;
+        p_sys->ps_pict_planes[i_plane].i_preview_size_y =
p_pic_in->p[i_plane].i_visible_lines * p_sys->s_current_param.i_preview_size
/ 100;
+
+        p_sys->ps_pict_planes[i_plane].i_border_size_x =
p_pic_in->p[i_plane].i_visible_pitch * p_sys->s_current_param.i_border / 2 /
100;
+        p_sys->ps_pict_planes[i_plane].i_border_size_y =
p_pic_in->p[i_plane].i_visible_pitch * p_sys->s_current_param.i_border / 2 /
100;
+
+        p_sys->ps_pict_planes[i_plane].i_pieces_max_x = ((
p_pic_in->p[i_plane].i_visible_pitch
+                - 2 * p_sys->ps_pict_planes[i_plane].i_border_size_x ) +
p_sys->s_allocated.i_cols - 1 ) / p_sys->s_allocated.i_cols;
+        p_sys->ps_pict_planes[i_plane].i_pieces_max_y = ((
p_pic_in->p[i_plane].i_visible_lines
+                - 2 * p_sys->ps_pict_planes[i_plane].i_border_size_y ) +
p_sys->s_allocated.i_rows - 1 ) / p_sys->s_allocated.i_rows;
+
+        for (int32_t r = 0; r < p_sys->s_allocated.i_rows; r++)
+            for (int32_t c = 0; c < p_sys->s_allocated.i_cols; c++)
+            {
+                if ( r == 0 )
+                    p_sys->ps_puzzle_array[r][c][i_plane].i_y =
p_sys->ps_pict_planes[i_plane].i_border_size_y;
+                if ( c == 0 )
+                    p_sys->ps_puzzle_array[r][c][i_plane].i_x =
p_sys->ps_pict_planes[i_plane].i_border_size_x;
+                p_sys->ps_puzzle_array[r][c][i_plane].i_size_x =
+                    (p_pic_dst->p[i_plane].i_visible_pitch -
p_sys->ps_pict_planes[i_plane].i_border_size_x
+                    - p_sys->ps_puzzle_array[r][c][i_plane].i_x) / (
p_sys->s_allocated.i_cols - c );
+                p_sys->ps_puzzle_array[r][c][i_plane].i_size_y =
+                    (p_pic_dst->p[i_plane].i_visible_lines -
p_sys->ps_pict_planes[i_plane].i_border_size_y
+                    - p_sys->ps_puzzle_array[r][c][i_plane].i_y) / (
p_sys->s_allocated.i_rows - r );
+                p_sys->ps_puzzle_array[r][c + 1][i_plane].i_x =
+                    p_sys->ps_puzzle_array[r][c][i_plane].i_x +
p_sys->ps_puzzle_array[r][c][i_plane].i_size_x;
+                p_sys->ps_puzzle_array[r + 1][c][i_plane].i_y =
+                    p_sys->ps_puzzle_array[r][c][i_plane].i_y +
p_sys->ps_puzzle_array[r][c][i_plane].i_size_y;
+            }
+    }
+
+    p_sys->i_magnet_accuracy = ( p_sys->s_current_param.i_pict_width / 50)
+ 3;
+
+    return 0;
+}
+
+static void free_ps_puzzle_array( filter_t *p_filter)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if (p_sys->ps_puzzle_array != NULL) {
+        for (int32_t r=0; r < p_sys->s_allocated.i_rows + 1; r++) {
+            for (int32_t c=0; c < p_sys->s_allocated.i_cols + 1; c++)
+                free( p_sys->ps_puzzle_array[r][c] );
+            free( p_sys->ps_puzzle_array[r] );
+        }
+        free( p_sys->ps_puzzle_array );
+    }
+    p_sys->ps_puzzle_array = NULL;
+
+    if (p_sys->ps_desk_planes != NULL)
+        free ( p_sys->ps_desk_planes );
+    p_sys->ps_desk_planes = NULL;
+
+    if (p_sys->ps_pict_planes != NULL)
+        free ( p_sys->ps_pict_planes );
+    p_sys->ps_pict_planes = NULL;
+
+    return;
+}
+
+static int bake_piece( filter_t *p_filter)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+    free_ps_pieces(p_filter);
+
+    p_sys->s_allocated.i_pieces_nbr = p_sys->s_allocated.i_rows *
p_sys->s_allocated.i_cols;
+    p_sys->ps_pieces = malloc( sizeof( piece_t) *
p_sys->s_allocated.i_pieces_nbr );
+    if( !p_sys->ps_pieces )
+        return VLC_ENOMEM;
+    for (uint32_t p = 0; p < p_sys->s_allocated.i_pieces_nbr; p++)
+    {
+        p_sys->ps_pieces[p].ps_piece_in_plane = malloc( sizeof(
piece_in_plane_t) * p_sys->s_allocated.i_planes );
+        if( !p_sys->ps_pieces[p].ps_piece_in_plane )
+            return VLC_ENOMEM;
+    }
+
+    p_sys->ps_pieces_tmp = malloc( sizeof( piece_t) *
p_sys->s_allocated.i_pieces_nbr );
+    p_sys->pi_group_qty = malloc( sizeof( int32_t ) *
(p_sys->s_allocated.i_pieces_nbr));
+
+    Shuffle( p_filter );
+
+    int32_t i;
+
+    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 = row;
+            int32_t ocol = col;
+
+            if (p_sys->pi_order != NULL) {
+                orow = p_sys->pi_order[i] / (p_sys->s_allocated.i_cols);
+                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_left_shape = 0;
+            p_sys->ps_pieces[i].i_top_shape = 2;
+            p_sys->ps_pieces[i].i_btm_shape = 4;
+            p_sys->ps_pieces[i].i_right_shape = 6;
+
+            if (p_sys->s_allocated.i_shape_size > 0)
+            {
+                if (orow < p_sys->s_allocated.i_rows - 1)
+                {
+                    p_sys->ps_pieces[i].i_btm_shape = 4 + 8 + 8*((
(unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
+                }
+
+                if (ocol < p_sys->s_allocated.i_cols - 1)
+                {
+                    p_sys->ps_pieces[i].i_right_shape = 6 + 8 + 8*((
(unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
+                }
+
+            }
+
+            p_sys->ps_pieces[i].i_actual_angle = 0;
+            p_sys->ps_pieces[i].b_overlap = false;
+            p_sys->ps_pieces[i].i_actual_mirror = +1;
+            p_sys->ps_pieces[i].b_finished = ((ocol == col) && (orow ==
row));
+            p_sys->ps_pieces[i].i_group_ID = i;
+
+            int32_t i_rand_x = 0;
+            int32_t i_rand_y = 0;
+            if (p_sys->s_current_param.b_advanced)
+            {
+                i_rand_x = (( (unsigned) vlc_mrand48()) % (
p_sys->ps_desk_planes[0].i_pieces_max_x + 1 ) ) - (int32_t)
p_sys->ps_desk_planes[0].i_pieces_max_x / 2;
+                i_rand_y = (( (unsigned) vlc_mrand48()) % (
p_sys->ps_desk_planes[0].i_pieces_max_y + 1 ) ) - (int32_t)
p_sys->ps_desk_planes[0].i_pieces_max_y / 2;
+            }
+
+            if (p_sys->ps_puzzle_array != NULL) {
+                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_size_x
= p_sys->ps_puzzle_array[row][col][i_plane].i_size_x; // here we use col
instead of ocol
+                    p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_size_y
= p_sys->ps_puzzle_array[row][col][i_plane].i_size_y;
+
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 + i_rand_x *
+                        p_sys->ps_desk_planes[i_plane].i_visible_pitch /
p_sys->ps_desk_planes[0].i_visible_pitch;
+
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_rand_y *
+                        p_sys->ps_desk_planes[i_plane].i_visible_lines /
p_sys->ps_desk_planes[0].i_visible_lines;
+
+                    if (i_plane == 0) {
+
+                        p_sys->ps_pieces[i].i_OLx =
p_sys->ps_pieces[i].ps_piece_in_plane[0].i_original_x;
+                        p_sys->ps_pieces[i].i_OTy =
p_sys->ps_pieces[i].ps_piece_in_plane[0].i_original_y;
+                        p_sys->ps_pieces[i].i_ORx =
p_sys->ps_pieces[i].ps_piece_in_plane[0].i_original_x +
p_sys->ps_pieces[i].ps_piece_in_plane[0].i_size_x - 1;
+                        p_sys->ps_pieces[i].i_OBy =
p_sys->ps_pieces[i].ps_piece_in_plane[0].i_original_y +
p_sys->ps_pieces[i].ps_piece_in_plane[0].i_size_y - 1;
+
+                        calculate_corners( p_filter, i );
+                    }
+                }
+            }
+            i++;
+        }
+    }
+
+    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 = row;
+            int32_t ocol = col;
+
+            if (p_sys->pi_order != NULL) {
+                orow = p_sys->pi_order[i] / (p_sys->s_allocated.i_cols);
+                ocol = p_sys->pi_order[i] % (p_sys->s_allocated.i_cols);
+            }
+
+            if (p_sys->s_allocated.i_shape_size > 0)
+            {
+                if (ocol > 0)
+                {
+                    for (uint16_t i_pce=0; i_pce <
p_sys->s_allocated.i_pieces_nbr; i_pce++)
+                    {
+                        if ((p_sys->ps_pieces[i_pce].i_original_row ==
orow) && (p_sys->ps_pieces[i_pce].i_original_col == ocol-1))
+                        {
+                            p_sys->ps_pieces[i].i_left_shape =
(p_sys->ps_pieces[i_pce].i_right_shape - 6 ) ^ 0x01;
+                            break;
+                        }
+                    }
+                }
+
+                if (orow > 0)
+                {
+                    for (uint16_t i_pce=0; i_pce <
p_sys->s_allocated.i_pieces_nbr; i_pce++)
+                    {
+                        if ((p_sys->ps_pieces[i_pce].i_original_row == orow
- 1) && (p_sys->ps_pieces[i_pce].i_original_col == ocol))
+                        {
+                            p_sys->ps_pieces[i].i_top_shape =
(p_sys->ps_pieces[i_pce].i_btm_shape - 2 ) ^ 0x01;
+                            break;
+                        }
+                    }
+                }
+            }
+            i++;
+        }
+    }
+
+    for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++)
+    {
+        p_sys->ps_pieces[i].i_actual_angle = 0;
+        p_sys->ps_pieces[i].i_actual_mirror = +1;
+
+        switch ( p_sys->s_current_param.i_rotate )
+        {
+          case 1:
+                rotate_pce( p_filter, i, (( (unsigned) vlc_mrand48()) % ( 2
) ) * 2, p_sys->ps_pieces[i].i_center_x, p_sys->ps_pieces[i].i_center_y,
false );
+            break;
+          case 2:
+                rotate_pce( p_filter, i, (( (unsigned) vlc_mrand48()) % ( 4
) ), p_sys->ps_pieces[i].i_center_x, p_sys->ps_pieces[i].i_center_y, false
);
+            break;
+          case 3:
+                rotate_pce( p_filter, i, (( (unsigned) vlc_mrand48()) % ( 8
) ), p_sys->ps_pieces[i].i_center_x, p_sys->ps_pieces[i].i_center_y, false
);
+            break;
+        }
+
+    }
+
+    return 0;
+}
+
+static void free_ps_pieces( filter_t *p_filter)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if (p_sys->ps_pieces != NULL) {
+        for (uint32_t i_pce = 0; i_pce < p_sys->s_allocated.i_pieces_nbr;
i_pce++)
+            free( p_sys->ps_pieces[i_pce].ps_piece_in_plane );
+        free( p_sys->ps_pieces );
+    }
+    p_sys->ps_pieces = NULL;
+
+    if (p_sys->pi_order != NULL)
+        free( p_sys->pi_order );
+    p_sys->pi_order = NULL;
+
+    if (p_sys->ps_pieces_tmp != NULL)
+        free( p_sys->ps_pieces_tmp );
+    p_sys->ps_pieces_tmp = NULL;
+
+    if (p_sys->pi_group_qty != NULL)
+        free( p_sys->pi_group_qty );
+    p_sys->pi_group_qty = NULL;
+
+    return;
+}
+
+static int bake_pieces_shapes( filter_t *p_filter)
+{
+// note:
+//   piece_shape_t **ps_pieces_shapes; // array [each piece type
(PCE_TYPE_NBR  * 4 ( * negative ): top, left,right,btm)][each plane] of
piece definition
+//   0 => left border
+//   1 => left border (negative, never used)
+//   2 => top border
+//   .....
+//   8 => bezier left
+//   9 => bezier left negative
+//  10 => bezier top
+//  11 => bezier top negative
+//  12 => bezier btm
+//  13 => bezier btm negative
+//  14 => bezier right
+//  15 => bezier right negative
+//   .....
+
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    free_ps_pieces_shapes(p_filter);
+    p_sys->ps_pieces_shapes = malloc( sizeof( piece_shape_t *) *
PIECE_TYPE_NBR );
+    if( !p_sys->ps_pieces_shapes )
+        return VLC_ENOMEM;
+
+    for (int32_t i_piece = 0; i_piece < PIECE_TYPE_NBR; i_piece++)
+    {
+        p_sys->ps_pieces_shapes[i_piece] = malloc( sizeof( piece_shape_t) *
p_sys->s_allocated.i_planes );
+        if( !p_sys->ps_pieces_shapes[i_piece] )
+            return VLC_ENOMEM;
+        for (uint8_t i_plane = 0; i_plane <
p_filter->p_sys->s_allocated.i_planes; i_plane++)
+        {
+            p_sys->ps_pieces_shapes[i_piece][i_plane].i_row_nbr = 0;
+            p_sys->ps_pieces_shapes[i_piece][i_plane].ps_piece_shape_row =
NULL;
+        }
+    }
+
+    int32_t i_currect_shape = 0;
+
+    for (uint8_t i_plane = 0; i_plane <
p_filter->p_sys->s_allocated.i_planes; i_plane++)
+    {
+        generate_sectLeftB( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+0][i_plane], i_plane);
+        generate_sectLeftB( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+1][i_plane], i_plane);
+        generate_sectTopB( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+2][i_plane], i_plane);
+        generate_sectTopB( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+3][i_plane], i_plane);
+        generate_sectBtmB( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+4][i_plane], i_plane);
+        generate_sectBtmB( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+5][i_plane], i_plane);
+        generate_sectRightB( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+6][i_plane], i_plane);
+        generate_sectRightB( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+7][i_plane], i_plane);
+    }
+
+    i_currect_shape += 8;
+
+    int32_t i_size_x = p_sys->ps_desk_planes[0].i_pieces_max_x;
+    int32_t i_size_y = p_sys->ps_desk_planes[0].i_pieces_max_y;
+
+    for (int32_t i_shape = 0; i_shape<SHAPES_QTY; i_shape++)
+    {
+
+        point_t *ps_scale_pts_H = scale_curve_H(i_size_x, i_size_y, 7,
p_sys->ps_bezier_pts_H[i_shape], p_sys->s_allocated.i_shape_size);
+        point_t *ps_scale_pts_V = H_2_scale_curve_V(i_size_x, i_size_y, 7,
p_sys->ps_bezier_pts_H[i_shape], p_sys->s_allocated.i_shape_size);
+        point_t *ps_neg_pts_H = curve_H_2_negative(7, ps_scale_pts_H);
+        point_t *ps_neg_pts_V = curve_V_2_negative(7, ps_scale_pts_V);
+
+        for (uint8_t i_plane = 0; i_plane <
p_filter->p_sys->s_allocated.i_planes; i_plane++)
+        {
+
+            generate_sectLeft( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape][i_plane], 7, ps_scale_pts_V,
i_plane);
+            generate_sectLeft( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+1][i_plane], 7, ps_neg_pts_V,
i_plane);
+            generate_sectTop( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+2][i_plane], 7, ps_scale_pts_H,
i_plane);
+            generate_sectTop( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+3][i_plane], 7, ps_neg_pts_H,
i_plane);
+
+            generate_sectTop2Btm( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+4][i_plane],
&p_sys->ps_pieces_shapes[i_currect_shape+2][i_plane], i_plane);
+            generate_sectTop2Btm( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+5][i_plane],
&p_sys->ps_pieces_shapes[i_currect_shape+3][i_plane], i_plane);
+            generate_sectLeft2Right( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+6][i_plane],
&p_sys->ps_pieces_shapes[i_currect_shape][i_plane], i_plane);
+            generate_sectLeft2Right( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+7][i_plane],
&p_sys->ps_pieces_shapes[i_currect_shape+1][i_plane], i_plane);
+
+        }
+
+        free(ps_scale_pts_H);
+        free(ps_scale_pts_V);
+        free(ps_neg_pts_H);
+        free(ps_neg_pts_V);
+
+        i_currect_shape += 8;
+    }
+
+    p_sys->b_shape_init = true;
+
+    return 0;
+}
+
+static void free_ps_pieces_shapes( filter_t *p_filter)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if (p_sys->ps_pieces_shapes != NULL)
+    {
+        for (int32_t p = 0; p < p_sys->s_allocated.i_piece_types; p++)
+        {
+            for (uint8_t i_plane = 0; i_plane <
p_sys->s_allocated.i_planes; i_plane++)
+            {
+                for (int32_t r = 0; r <
p_sys->ps_pieces_shapes[p][i_plane].i_row_nbr; r++)
+                    free(
p_sys->ps_pieces_shapes[p][i_plane].ps_piece_shape_row[r].ps_row_section );
+                free(
p_sys->ps_pieces_shapes[p][i_plane].ps_piece_shape_row );
+            }
+            free( p_sys->ps_pieces_shapes[p] );
+        }
+        free( p_sys->ps_pieces_shapes );
+        p_sys->ps_pieces_shapes = NULL;
+    }
+
+    return;
+}
+
+static bool IsValid( filter_sys_t *p_sys, int32_t *pi_pce_lst )
+{
+    const int32_t i_count = p_sys->s_allocated.i_pieces_nbr;
+
+    if( !p_sys->s_current_param.b_blackslot )
+        return true;
+
+    int32_t d = 0;
+    for( int32_t i = 0; i < i_count; i++ )
+    {
+        if( pi_pce_lst[i] == i_count - 1 )
+        {
+            d += i / p_sys->s_allocated.i_cols + 1;
+            continue;
+        }
+        for( int32_t j = i+1; j < i_count; j++ )
+        {
+            if( pi_pce_lst[j] == i_count - 1 )
+                continue;
+            if( pi_pce_lst[i] > pi_pce_lst[j] )
+                d++;
+        }
+    }
+    return (d%2) == 0;
+}
+
+static void Shuffle( filter_t *p_filter )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    int32_t i_pieces_nbr = p_sys->s_allocated.i_pieces_nbr;
+
+    do
+    {
+        generate_rand_pce_list( p_filter, &p_sys->pi_order );
+    } while( IsFinished( p_sys, p_sys->pi_order ) || !IsValid( p_sys,
p_sys->pi_order ) );
+
+
+    if( p_sys->s_current_param.b_blackslot )
+    {
+        for( int32_t i = 0; i < i_pieces_nbr; i++ )
+            if( p_sys->pi_order[i] == i_pieces_nbr - 1 )
+            {
+                p_sys->i_selected = i;
+                break;
+            }
+    }
     else
     {
         p_sys->i_selected = -1;
     }
+
+    p_sys->b_shuffleRqst = false;
+    p_sys->b_finished = false;
+}
+
+static void generate_rand_pce_list( filter_t *p_filter, int32_t
**pi_pce_lst )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    int32_t i_pieces_nbr = p_sys->s_allocated.i_pieces_nbr;
+
+    if (pi_pce_lst != NULL )
+        free( *pi_pce_lst );
+    *pi_pce_lst = calloc( i_pieces_nbr, sizeof(**pi_pce_lst) );
+
+    for( int32_t i = 0; i < i_pieces_nbr; i++ )
+        (*pi_pce_lst)[i] = -1;
+
+    for( int32_t c = 0; c < i_pieces_nbr; )
+    {
+        int32_t i = ((unsigned)vlc_mrand48()) % i_pieces_nbr;
+        if( (*pi_pce_lst)[i] == -1 )
+            (*pi_pce_lst)[i] = c++;
+    }
+}
+
+static bool IsFinished( filter_sys_t *p_sys, int32_t *pi_pce_lst )
+{
+    for( uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++ )
+    {
+        if( (int32_t)i != pi_pce_lst[i] )
+            return false;
+    }
+    return true;
+}
+
+static int find_piece( filter_t *p_filter, int32_t i_x, int32_t i_y,
int32_t i_except) {
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
+        piece_t *ps_current_piece = &p_sys->ps_pieces[i];
+        if (( ps_current_piece->i_min_x <= i_x ) &&
+            ( ps_current_piece->i_max_x >= i_x ) &&
+            ( ps_current_piece->i_min_y <= i_y ) &&
+            ( ps_current_piece->i_max_y  >= i_y ) &&
+            ( (int32_t)i != i_except ) )
+        {
+            return i;
+        }
+    }
+    return -1;
+}
+
+static void calculate_corners( filter_t *p_filter,  int32_t i_piece )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+    piece_t *ps_piece = &p_sys->ps_pieces[i_piece];
+
+    switch ( ps_piece->i_actual_angle)
+    {
+      case 0:
+        ps_piece->i_step_x_x = ps_piece->i_actual_mirror;
+        ps_piece->i_step_x_y = 0;
+        ps_piece->i_step_y_y = 1;
+        ps_piece->i_step_y_x = 0;
+        break;
+      case 1:
+        ps_piece->i_step_x_x = 0;
+        ps_piece->i_step_x_y = -ps_piece->i_actual_mirror; // x offset on
original pict creates negative y offset on desk
+        ps_piece->i_step_y_y = 0;
+        ps_piece->i_step_y_x = 1;
+        break;
+      case 2:
+        ps_piece->i_step_x_x = -ps_piece->i_actual_mirror;
+        ps_piece->i_step_x_y = 0;
+        ps_piece->i_step_y_y = -1;
+        ps_piece->i_step_y_x = 0;
+        break;
+      case 3:
+        ps_piece->i_step_x_x = 0;
+        ps_piece->i_step_x_y = ps_piece->i_actual_mirror;
+        ps_piece->i_step_y_y = 0;
+        ps_piece->i_step_y_x = -1;
+        break;
+    }
+
+    //regen geometry
+    for (uint8_t i_plane = 1; i_plane < p_sys->s_allocated.i_planes;
i_plane++) {
+        ps_piece->ps_piece_in_plane[i_plane].i_actual_x =
+            ps_piece->ps_piece_in_plane[0].i_actual_x *
p_sys->ps_desk_planes[i_plane].i_visible_pitch /
p_sys->ps_desk_planes[0].i_visible_pitch;
+        ps_piece->ps_piece_in_plane[i_plane].i_actual_y =
+            ps_piece->ps_piece_in_plane[0].i_actual_y *
p_sys->ps_desk_planes[i_plane].i_visible_lines /
p_sys->ps_desk_planes[0].i_visible_lines;
+    }
+
+    // regen location of grabed piece's corners
+    int32_t i_size_x = ps_piece->ps_piece_in_plane[0].i_size_x;
+    int32_t i_size_y = ps_piece->ps_piece_in_plane[0].i_size_y;
+
+    ps_piece->i_TLx = ps_piece->ps_piece_in_plane[0].i_actual_x;
+    ps_piece->i_TLy = ps_piece->ps_piece_in_plane[0].i_actual_y;
+    ps_piece->i_TRx = ps_piece->i_TLx + ( i_size_x - 1 ) *
ps_piece->i_step_x_x;
+    ps_piece->i_TRy = ps_piece->i_TLy + ( i_size_x - 1 ) *
ps_piece->i_step_x_y;
+    ps_piece->i_BRx = ps_piece->i_TLx + ( i_size_x - 1 ) *
ps_piece->i_step_x_x + ( i_size_y - 1 ) * ps_piece->i_step_y_x;
+    ps_piece->i_BRy = ps_piece->i_TLy + ( i_size_x - 1 ) *
ps_piece->i_step_x_y + ( i_size_y - 1 ) * ps_piece->i_step_y_y;
+    ps_piece->i_BLx = ps_piece->i_TLx + ( i_size_y - 1 ) *
ps_piece->i_step_y_x;
+    ps_piece->i_BLy = ps_piece->i_TLy + ( i_size_y - 1 ) *
ps_piece->i_step_y_y;
+
+    ps_piece->i_max_x = MAX( MAX( ps_piece->i_TLx, ps_piece->i_TRx ), MAX(
ps_piece->i_BLx, ps_piece->i_BRx ) );
+    ps_piece->i_min_x = MIN( MIN( ps_piece->i_TLx, ps_piece->i_TRx ), MIN(
ps_piece->i_BLx, ps_piece->i_BRx ) );
+    ps_piece->i_max_y = MAX( MAX( ps_piece->i_TLy, ps_piece->i_TRy ), MAX(
ps_piece->i_BLy, ps_piece->i_BRy ) );
+    ps_piece->i_min_y = MIN( MIN( ps_piece->i_TLy, ps_piece->i_TRy ), MIN(
ps_piece->i_BLy, ps_piece->i_BRy ) );
+
+    ps_piece->i_center_x = ( ps_piece->i_max_x + ps_piece->i_min_x ) / 2;
+    ps_piece->i_center_y = ( ps_piece->i_max_y + ps_piece->i_min_y ) / 2;
+
+    int32_t pce_overlap = find_piece( p_filter, ps_piece->i_center_x,
ps_piece->i_center_y, i_piece);
+
+    if ( ( pce_overlap != -1 ) && (
p_sys->pi_group_qty[ps_piece->i_group_ID] == 1 ) )
+        ps_piece->b_overlap = true;
+}
+
+static void piece_foreground( filter_t *p_filter, int32_t i_piece) {
+    filter_sys_t *p_sys = p_filter->p_sys;
+    piece_t *ps_pieces_tmp; // list [piece] of pieces data. Sort as per
layers
+    int32_t i_group_ID = p_sys->ps_pieces[i_piece].i_group_ID;
+
+    ps_pieces_tmp = malloc( sizeof( piece_t) *
p_sys->s_allocated.i_pieces_nbr );
+
+    int32_t j=0;
+
+    memcpy( &ps_pieces_tmp[j], &p_sys->ps_pieces[i_piece], sizeof(piece_t)
);
+    j++;
+
+    for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
+        if ( ( p_sys->ps_pieces[i].i_group_ID == i_group_ID ) && (
(int32_t)i != i_piece ) ) {
+            memcpy( &ps_pieces_tmp[j], &p_sys->ps_pieces[i],
sizeof(piece_t));
+            j++;
+        }
+    }
+    for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
+        if ( p_sys->ps_pieces[i].i_group_ID != i_group_ID ) {
+            memcpy( &ps_pieces_tmp[j], &p_sys->ps_pieces[i],
sizeof(piece_t));
+            j++;
+        }
+    }
+
+    free( p_filter->p_sys->ps_pieces );
+    p_filter->p_sys->ps_pieces = ps_pieces_tmp;
+
+}
+
+static void count_pce_group( filter_t *p_filter) { // count pce in each
group
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    memset ( p_sys->pi_group_qty, (int32_t) 0, sizeof( int32_t ) *
(p_sys->s_allocated.i_pieces_nbr) );
+    for (uint32_t i_pce = 0; i_pce < p_sys->s_allocated.i_pieces_nbr;
i_pce++)
+        p_sys->pi_group_qty[p_sys->ps_pieces[i_pce].i_group_ID]++;
+}
+
+static void solve_pces_group( filter_t *p_filter) {
+    filter_sys_t *p_sys = p_filter->p_sys;
+    int32_t i_dx, i_dy;
+
+    p_sys->i_solve_grp_loop++;
+    p_sys->i_solve_grp_loop %= p_sys->s_allocated.i_pieces_nbr;
+
+    int32_t i_piece_A = p_sys->i_solve_grp_loop;
+    piece_t *ps_piece_A = &p_sys->ps_pieces[i_piece_A];
+
+    for (uint32_t i_piece_B = 0; i_piece_B <
p_sys->s_allocated.i_pieces_nbr; i_piece_B++) {
+        piece_t *ps_piece_B = &p_sys->ps_pieces[i_piece_B];
+        if ( ps_piece_A->i_actual_angle == ps_piece_B->i_actual_angle &&
ps_piece_A->i_actual_mirror == ps_piece_B->i_actual_mirror ) {
+            if ( (ps_piece_B->i_group_ID !=
p_sys->ps_pieces[i_piece_A].i_group_ID ) ) {
+                if ( abs(ps_piece_A->i_OTy - ps_piece_B->i_OTy )<3) {
+                    if (abs( ps_piece_A->i_ORx - ps_piece_B->i_OLx + 1 )<3)
{
+                        if ( ( abs( ps_piece_A->i_TRx - ps_piece_B->i_TLx +
1 ) < p_sys->i_magnet_accuracy ) && ( abs( ps_piece_A->i_TRy -
ps_piece_B->i_TLy ) < p_sys->i_magnet_accuracy ) &&
+                             ( abs( ps_piece_A->i_BRx - ps_piece_B->i_BLx +
1 ) < p_sys->i_magnet_accuracy ) && ( abs( ps_piece_A->i_BRy -
ps_piece_B->i_BLy ) < p_sys->i_magnet_accuracy ) ) {
+
+                            i_dx = ps_piece_A->i_TRx - ps_piece_B->i_TLx +
ps_piece_A->i_step_x_x;
+                            i_dy = ps_piece_A->i_TRy - ps_piece_B->i_TLy;
+
+                            if (!ps_piece_B->b_finished) {
+                                move_group( p_filter, i_piece_B, i_dx,
i_dy);
+                            }
+                            else {
+                                move_group( p_filter, i_piece_A, -i_dx,
-i_dy);
+                            }
+
+                            int32_t i_group_ID = ps_piece_B->i_group_ID;
+                            for (uint32_t i_for = 0; i_for <
p_sys->s_allocated.i_pieces_nbr; i_for++)
+                                if ( p_sys->ps_pieces[i_for].i_group_ID ==
i_group_ID)
+                                    p_sys->ps_pieces[i_for].i_group_ID =
p_sys->ps_pieces[i_piece_A].i_group_ID;
+                        }
+                    }
+                }
+                else if ( abs(ps_piece_A->i_OLx - ps_piece_B->i_OLx )<3) {
+                    if ( abs(ps_piece_A->i_OBy - ps_piece_B->i_OTy + 1 )<3)
{
+                        if (  ( abs( ps_piece_B->i_TLx - ps_piece_A->i_BLx
) < p_sys->i_magnet_accuracy ) && ( abs( ps_piece_B->i_TLy - 1 -
ps_piece_A->i_BLy ) < p_sys->i_magnet_accuracy ) &&
+                              ( abs( ps_piece_B->i_TRx - ps_piece_A->i_BRx
) < p_sys->i_magnet_accuracy ) && ( abs( ps_piece_B->i_TRy - 1 -
ps_piece_A->i_BRy ) < p_sys->i_magnet_accuracy ) ) {
+
+                            i_dx = ps_piece_A->i_BLx - ps_piece_B->i_TLx;
+                            i_dy = ps_piece_A->i_BLy - ps_piece_B->i_TLy +
ps_piece_A->i_step_y_y;
+
+                            if (!ps_piece_B->b_finished) {
+                                move_group( p_filter, i_piece_B, i_dx,
i_dy);
+                            }
+                            else {
+                                move_group( p_filter, i_piece_A, -i_dx,
-i_dy);
+                            }
+
+                            int32_t i_group_ID = ps_piece_B->i_group_ID;
+                            for (uint32_t i_for = 0; i_for <
p_sys->s_allocated.i_pieces_nbr; i_for++)
+                                if ( p_sys->ps_pieces[i_for].i_group_ID ==
i_group_ID)
+                                    p_sys->ps_pieces[i_for].i_group_ID =
p_sys->ps_pieces[i_piece_A].i_group_ID;
+                        }
+                    }
+                }
+            }
+
+            if ( abs( ps_piece_A->i_OTy - ps_piece_B->i_OTy )<3 ) {
+                if ( abs( ps_piece_A->i_ORx - ps_piece_B->i_OLx + 1 )<3 ) {
+                    if ( ( abs( ps_piece_A->i_TRx - ps_piece_B->i_TLx + 1 )
< p_sys->i_magnet_accuracy ) && ( abs( ps_piece_A->i_TRy - ps_piece_B->i_TLy
) < p_sys->i_magnet_accuracy ) &&
+                         ( abs( ps_piece_A->i_BRx - ps_piece_B->i_BLx + 1 )
< p_sys->i_magnet_accuracy ) && ( abs( ps_piece_A->i_BRy - ps_piece_B->i_BLy
) < p_sys->i_magnet_accuracy ) ) {
+
+                        ps_piece_B->i_left_shape = 0;
+                        ps_piece_A->i_right_shape = 6;
+                    }
+                }
+            }
+            else if ( abs( ps_piece_A->i_OLx - ps_piece_B->i_OLx )<3 ) {
+                if ( abs( ps_piece_A->i_OBy - ps_piece_B->i_OTy + 1 )<3 ) {
+                    if (  ( abs( ps_piece_B->i_TLx - ps_piece_A->i_BLx ) <
p_sys->i_magnet_accuracy ) && ( abs( ps_piece_B->i_TLy - 1 -
ps_piece_A->i_BLy ) < p_sys->i_magnet_accuracy ) &&
+                          ( abs( ps_piece_B->i_TRx - ps_piece_A->i_BRx ) <
p_sys->i_magnet_accuracy ) && ( abs( ps_piece_B->i_TRy - 1 -
ps_piece_A->i_BRy ) < p_sys->i_magnet_accuracy ) ) {
+
+                        ps_piece_B->i_top_shape = 2;
+                        ps_piece_A->i_btm_shape = 4;
+                    }
+                }
+            }
+        }
+   }
+}
+
+static void solve_pces_accuracy( filter_t *p_filter) {
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    p_sys->i_solve_acc_loop++;
+    if (p_sys->i_solve_acc_loop >= p_sys->s_allocated.i_pieces_nbr) {
+        p_sys->i_done_count = p_sys->i_tmp_done_count;
+        p_sys->i_tmp_done_count = 0;
+        p_sys->i_solve_acc_loop = 0;
+        p_sys->b_finished = (p_sys->i_done_count ==
p_sys->s_allocated.i_pieces_nbr);
+    }
+
+    piece_t *ps_piece = &p_sys->ps_pieces[p_sys->i_solve_acc_loop];
+
+    ps_piece->b_finished = false;
+    if ( ps_piece->i_actual_mirror == 1 )
+        if ( abs( ps_piece->i_TRx - ps_piece->i_ORx )  <
p_sys->i_magnet_accuracy )
+            if ( abs( ps_piece->i_TRy - ps_piece->i_OTy )  <
p_sys->i_magnet_accuracy )
+                if ( abs( ps_piece->i_TLx - ps_piece->i_OLx )  <
p_sys->i_magnet_accuracy )
+                    if ( abs( ps_piece->i_TLy - ps_piece->i_OTy )  <
p_sys->i_magnet_accuracy ) {
+                        int32_t i_group_ID = ps_piece->i_group_ID;
+                        p_sys->i_tmp_done_count++;
+
+                        for ( uint32_t i = 0; i <
p_sys->s_allocated.i_pieces_nbr; i++) {
+                            ps_piece = &p_sys->ps_pieces[i];
+                            if ( ( ps_piece->i_group_ID == i_group_ID ) &&
( !ps_piece->b_finished ) ) {
+                                ps_piece->ps_piece_in_plane[0].i_actual_x =
ps_piece->i_OLx;
+                                ps_piece->ps_piece_in_plane[0].i_actual_y =
ps_piece->i_OTy;
+                                ps_piece->i_actual_mirror = +1;
+                                calculate_corners( p_filter, i );
+                                ps_piece->b_finished = true;
+                            }
+                        }
+                    }
+}
+
+static void sort_layers( filter_t *p_filter)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    // sort
+    int32_t i_idx = 0;
+    for (uint32_t i_qty = 1; i_qty <= p_sys->s_current_param.i_pieces_nbr;
i_qty++)
+    {   // pieces at the wrong place are in foreground
+        for (uint32_t i_pce_loop = 0; i_pce_loop <
p_sys->s_current_param.i_pieces_nbr; i_pce_loop++)
+        {
+            int32_t i_grp = p_sys->ps_pieces[i_pce_loop].i_group_ID;
+            if ( p_sys->pi_group_qty[i_grp] == (int32_t)i_qty )
+            {
+                bool b_check_ok = true;
+                for (int32_t i_pce_check = 0; i_pce_check < i_idx;
i_pce_check++)
+                    if ( p_sys->ps_pieces_tmp[i_pce_check].i_group_ID ==
i_grp )
+                        b_check_ok = false;
+                if ( b_check_ok )
+                {
+                    for (uint32_t i_pce = i_pce_loop; i_pce <
p_sys->s_current_param.i_pieces_nbr; i_pce++)
+                        if (( p_sys->ps_pieces[i_pce].i_group_ID == i_grp )
&& !p_sys->ps_pieces[i_pce].b_finished )
+                        {
+                            memcpy( &p_sys->ps_pieces_tmp[i_idx],
&p_sys->ps_pieces[i_pce], sizeof(piece_t));
+                            i_idx++;
+                        }
+                }
+            }
+        }
+        // pieces at the final location are in background
+        for (uint32_t i_pce_loop = 0; i_pce_loop <
p_sys->s_current_param.i_pieces_nbr; i_pce_loop++)
+        {
+            int32_t i_grp = p_sys->ps_pieces[i_pce_loop].i_group_ID;
+            if ( p_sys->pi_group_qty[i_grp] == (int32_t)i_qty )
+            {
+                bool b_check_ok = true;
+                for (int32_t i_pce_check = 0; i_pce_check < i_idx;
i_pce_check++)
+                    if ( p_sys->ps_pieces_tmp[i_pce_check].i_group_ID ==
i_grp && p_sys->ps_pieces_tmp[i_pce_check].b_finished )
+                        b_check_ok = false;
+                if ( b_check_ok )
+                {
+                    for (uint32_t i_pce = i_pce_loop; i_pce <
p_sys->s_current_param.i_pieces_nbr; i_pce++)
+                        if (( p_sys->ps_pieces[i_pce].i_group_ID == i_grp )
&& p_sys->ps_pieces[i_pce].b_finished )
+                        {
+                            memcpy( &p_sys->ps_pieces_tmp[i_idx],
&p_sys->ps_pieces[i_pce], sizeof(piece_t));
+                            i_idx++;
+                        }
+                }
+            }
+        }
+    }
+
+    free( p_filter->p_sys->ps_pieces );
+    p_filter->p_sys->ps_pieces = p_sys->ps_pieces_tmp;
+    p_sys->ps_pieces_tmp = malloc( sizeof( piece_t) *
p_sys->s_allocated.i_pieces_nbr );
+}
+
+static void rotate_pce( filter_t *p_filter, int32_t i_piece, int8_t
i_rotate_mirror, int32_t i_center_x, int32_t i_center_y, bool b_avoid_mirror
)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+    piece_t *ps_piece = &p_sys->ps_pieces[i_piece];
+
+    if ( p_sys->s_current_param.i_rotate == 0 )
+        return;
+
+    if ( p_sys->s_current_param.i_rotate == 1 && (i_rotate_mirror != 2) )
+        return;
+
+    for ( uint8_t i=0; i < abs( i_rotate_mirror ); i++)
+    {
+        int32_t i_tempx, i_tempy;
+
+        // piece has to be rotated by 90°:
+        if ( i_rotate_mirror > 0 )
+        {
+            ps_piece->i_actual_angle++;
+            ps_piece->i_actual_angle &= 0x03;
+
+            i_tempx = -( i_center_y -
ps_piece->ps_piece_in_plane[0].i_actual_y ) + i_center_x;
+            i_tempy = +( i_center_x -
ps_piece->ps_piece_in_plane[0].i_actual_x ) + i_center_y;
+        }
+        else
+        {
+            ps_piece->i_actual_angle--;
+            ps_piece->i_actual_angle &= 0x03;
+
+            i_tempx = +( i_center_y -
ps_piece->ps_piece_in_plane[0].i_actual_y ) + i_center_x;
+            i_tempy = -( i_center_x -
ps_piece->ps_piece_in_plane[0].i_actual_x ) + i_center_y;
+        }
+
+        ps_piece->ps_piece_in_plane[0].i_actual_x = i_tempx;
+        ps_piece->ps_piece_in_plane[0].i_actual_y = i_tempy;
+
+        if ( ps_piece->i_actual_angle == 0 &&
p_sys->s_current_param.i_rotate == 3 && !b_avoid_mirror )
+        {
+            ps_piece->ps_piece_in_plane[0].i_actual_x = 2 * i_center_x -
ps_piece->ps_piece_in_plane[0].i_actual_x;
+            ps_piece->i_actual_mirror *= -1;
+        }
+        calculate_corners( p_filter, i_piece );
+    }
+}
+
+static void move_group( filter_t *p_filter, int32_t i_piece, int32_t i_dx,
int32_t i_dy)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+    int32_t i_group_ID = p_sys->ps_pieces[i_piece].i_group_ID;
+    for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
+        piece_t *ps_piece = &p_sys->ps_pieces[i];
+        if (ps_piece->i_group_ID == i_group_ID) {
+            ps_piece->b_finished = false;
+            ps_piece->ps_piece_in_plane[0].i_actual_x += i_dx;
+            ps_piece->ps_piece_in_plane[0].i_actual_y += i_dy;
+
+            calculate_corners( p_filter, i );
+        }
+    }
+}
+
+static void auto_solve( filter_t *p_filter)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if ( p_sys->s_current_param.i_auto_solve_speed < 500 )
+        return;
+
+    if ( --p_sys->i_auto_solve_countdown_val > 0 )
+        return;
+
+    // delay reached, preset next delay and proceed with auto_solve
+    p_sys->i_auto_solve_countdown_val =
init_countdown(p_sys->s_current_param.i_auto_solve_speed);
+
+    // random piece to be moved
+    int32_t i_start = ((unsigned)vlc_mrand48()) %
p_sys->s_allocated.i_pieces_nbr;
+
+    // here the computer will help player by placing the piece at the final
location:
+    for (uint32_t i_l = 0; i_l < p_sys->s_allocated.i_pieces_nbr; i_l++)
+    {
+        int32_t i = ( i_l + i_start ) % p_sys->s_allocated.i_pieces_nbr;
+        if ( !p_sys->ps_pieces[i].b_finished )
+        {
+            for (uint32_t j = 0; j < p_sys->s_allocated.i_pieces_nbr; j++)
+            {
+                if ( p_sys->ps_pieces[j].i_group_ID ==
p_sys->ps_pieces[i].i_group_ID )
+                {
+                    p_sys->ps_pieces[j].i_actual_angle = 0;
+                    p_sys->ps_pieces[j].i_actual_mirror = +1;
+                    p_sys->ps_pieces[j].ps_piece_in_plane[0].i_actual_x =
p_sys->ps_pieces[j].ps_piece_in_plane[0].i_original_x;
+                    p_sys->ps_pieces[j].ps_piece_in_plane[0].i_actual_y =
p_sys->ps_pieces[j].ps_piece_in_plane[0].i_original_y;
+                    calculate_corners( p_filter, j );
+                }
+            }
+            break;
+        }
+    }
+}
+
+static void auto_shuffle( filter_t *p_filter)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if ( p_sys->s_current_param.i_auto_shuffle_speed < 500 )
+        return;
+
+    if ( --p_sys->i_auto_shuffle_countdown_val > 0 )
+        return;
+
+    // delay reached, preset next delay and proceed with auto_shuffle
+    p_sys->i_auto_shuffle_countdown_val =
init_countdown(p_sys->s_current_param.i_auto_shuffle_speed);
+
+    // random piece to be moved
+    int32_t i_start = ((unsigned)vlc_mrand48()) %
p_sys->s_allocated.i_pieces_nbr;
+
+    for (uint32_t i_l = 0; i_l < p_sys->s_allocated.i_pieces_nbr; i_l++)
+    {
+        int32_t i = ( i_l + i_start ) % p_sys->s_allocated.i_pieces_nbr;
+
+        // find one piece which is part of one group
+        if ( p_sys->pi_group_qty[p_sys->ps_pieces[i].i_group_ID] > 1 )
+        {
+            // find an empty group to be used by this dismanteled piece
+            uint32_t i_new_group;
+            for ( i_new_group = 0 ; i_new_group <
p_sys->s_allocated.i_pieces_nbr ; i_new_group ++ )
+                if ( p_sys->pi_group_qty[i_new_group] == 0 )
+                    break;
+            p_sys->ps_pieces[i].i_group_ID = i_new_group;
+            p_sys->ps_pieces[i].b_finished = false;
+
+            //random rotate & mirror
+            switch ( p_sys->s_current_param.i_rotate )
+            {
+              case 1:
+                    rotate_pce( p_filter, i, (( (unsigned) vlc_mrand48()) %
( 2 ) ) * 2, p_sys->ps_pieces[i].i_center_x, p_sys->ps_pieces[i].i_center_y,
false );
+                break;
+              case 2:
+                    rotate_pce( p_filter, i, (( (unsigned) vlc_mrand48()) %
( 4 ) ), p_sys->ps_pieces[i].i_center_x, p_sys->ps_pieces[i].i_center_y,
false );
+                break;
+              case 3:
+                    rotate_pce( p_filter, i, (( (unsigned) vlc_mrand48()) %
( 8 ) ), p_sys->ps_pieces[i].i_center_x, p_sys->ps_pieces[i].i_center_y,
false );
+                break;
+            }
+
+            // random mvt
+            p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_x =
+                    p_sys->ps_desk_planes[0].i_border_size_x
+                    + ( (unsigned) vlc_mrand48()) % (
p_sys->ps_desk_planes[0].i_visible_pitch -
2*p_sys->ps_desk_planes[0].i_border_size_x -
p_sys->ps_pieces[i].ps_piece_in_plane[0].i_size_x)
+                    + p_sys->ps_pieces[i].ps_piece_in_plane[0].i_size_x / 2
* ( 1 - p_sys->ps_pieces[i].i_step_x_x )
+                    - (p_sys->ps_pieces[i].ps_piece_in_plane[0].i_size_y /
2) * p_sys->ps_pieces[i].i_step_y_x;
+            p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_y =
+                    p_sys->ps_desk_planes[0].i_border_size_y
+                    + ( (unsigned) vlc_mrand48()) % (
p_sys->ps_desk_planes[0].i_visible_lines -
2*p_sys->ps_desk_planes[0].i_border_size_y -
p_sys->ps_pieces[i].ps_piece_in_plane[0].i_size_y)
+                    + p_sys->ps_pieces[i].ps_piece_in_plane[0].i_size_y / 2
* ( 1 - p_sys->ps_pieces[i].i_step_y_y )
+                    - (p_sys->ps_pieces[i].ps_piece_in_plane[0].i_size_x /
2) * p_sys->ps_pieces[i].i_step_x_y;
+
+            // redefine shapes
+            uint32_t i_left_pce = 0;
+            uint32_t i_right_pce = 0;
+            uint32_t i_top_pce = 0;
+            uint32_t i_btm_pce = 0;
+
+            uint32_t i_pce = 0;
+            for (int32_t i_row = 0; i_row < p_sys->s_allocated.i_rows;
i_row++)
+                for (int32_t i_col = 0; i_col < p_sys->s_allocated.i_cols;
i_col++) {
+                    if (p_sys->ps_pieces[i].i_original_row ==
p_sys->ps_pieces[i_pce].i_original_row) {
+                        if (p_sys->ps_pieces[i].i_original_col ==
p_sys->ps_pieces[i_pce].i_original_col - 1)
+                            i_right_pce = i_pce;
+                        else if (p_sys->ps_pieces[i].i_original_col ==
p_sys->ps_pieces[i_pce].i_original_col + 1)
+                            i_left_pce = i_pce;
+                    }
+                    else if (p_sys->ps_pieces[i].i_original_col ==
p_sys->ps_pieces[i_pce].i_original_col) {
+                        if (p_sys->ps_pieces[i].i_original_row ==
p_sys->ps_pieces[i_pce].i_original_row - 1)
+                            i_btm_pce = i_pce;
+                        else if (p_sys->ps_pieces[i].i_original_row ==
p_sys->ps_pieces[i_pce].i_original_row + 1)
+                            i_top_pce = i_pce;
+                    }
+                    i_pce++;
+                }
+
+            if ((p_sys->ps_pieces[i].i_left_shape == 0) &&
(p_sys->ps_pieces[i].i_original_col != 0)) {
+                p_sys->ps_pieces[i_left_pce].i_right_shape = 6 + 8 + 8*((
(unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
+                p_sys->ps_pieces[i].i_left_shape =
(p_sys->ps_pieces[i_left_pce].i_right_shape - 6 ) ^ 0x01;
+            }
+
+            if ((p_sys->ps_pieces[i].i_right_shape == 6) &&
(p_sys->ps_pieces[i].i_original_col != p_sys->s_allocated.i_cols-1)) {
+                p_sys->ps_pieces[i].i_right_shape = 6 + 8 + 8*(( (unsigned)
vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
+                p_sys->ps_pieces[i_right_pce].i_left_shape =
(p_sys->ps_pieces[i].i_right_shape - 6 ) ^ 0x01;
+            }
+
+            if ((p_sys->ps_pieces[i].i_top_shape == 2) &&
(p_sys->ps_pieces[i].i_original_row != 0)) {
+                p_sys->ps_pieces[i_top_pce].i_btm_shape = 4 + 8 + 8*((
(unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
+                p_sys->ps_pieces[i].i_top_shape =
(p_sys->ps_pieces[i_top_pce].i_btm_shape - 2 ) ^ 0x01;
+            }
+
+            if ((p_sys->ps_pieces[i].i_btm_shape == 4) &&
(p_sys->ps_pieces[i].i_original_row != p_sys->s_allocated.i_rows-1)) {
+                p_sys->ps_pieces[i].i_btm_shape = 4 + 8 + 8*(( (unsigned)
vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
+                p_sys->ps_pieces[i_btm_pce].i_top_shape =
(p_sys->ps_pieces[i].i_btm_shape - 2 ) ^ 0x01;
+            }
+
+            calculate_corners( p_filter, i );
+            break;
+        }
+    }
+
+}
+
+static void puzzle_preset_background( picture_t *p_pic_dst, uint8_t Y,
uint8_t U, uint8_t V)
+{
+    uint8_t i_c;
+
+    for( uint8_t i_plane = 0; i_plane < p_pic_dst->i_planes; i_plane++ )
+    {
+        if (i_plane == Y_PLANE)
+            i_c = Y;
+        else if (i_plane == U_PLANE)
+            i_c = U;
+        else if (i_plane == V_PLANE)
+            i_c = V;
+
+        const int32_t i_dst_pitch = p_pic_dst->p[i_plane].i_pitch;
+        const int32_t i_dst_lines = p_pic_dst->p[i_plane].i_lines;
+
+        uint8_t *p_dst = p_pic_dst->p[i_plane].p_pixels;
+
+        for (int32_t y = 0; y < i_dst_lines; y++)
+            memset(&p_dst[y * i_dst_pitch], i_c, i_dst_pitch);
+    }
+}
+
+static void puzzle_draw_borders( filter_t *p_filter, picture_t *p_pic,
picture_t *p_pic_dst)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    for( uint8_t i_plane = 0; i_plane < p_pic_dst->i_planes; i_plane++ )
+    {
+        const int32_t i_pitch = p_sys->ps_pict_planes[i_plane].i_pitch;
+        const int32_t i_out_pitch = p_sys->ps_desk_planes[i_plane].i_pitch;
+        const int32_t i_vis_lines =
p_sys->ps_pict_planes[i_plane].i_visible_lines;
+        const int32_t i_vis_pitch =
p_sys->ps_pict_planes[i_plane].i_visible_pitch;
+        const int32_t i_border_size_x =
p_sys->ps_pict_planes[i_plane].i_border_size_x;
+        const int32_t i_border_size_y =
p_sys->ps_pict_planes[i_plane].i_border_size_y;
+
+        uint8_t *p_src = p_pic->p[i_plane].p_pixels;
+        uint8_t *p_dst = p_pic_dst->p[i_plane].p_pixels;
+
+        for (int32_t y = 0 ; y < i_border_size_y; y++)
+            memcpy( &p_dst[y * i_out_pitch], &p_src[y * i_pitch],
i_vis_pitch);
+
+        for (int32_t y = i_vis_lines - i_border_size_y ; y < i_vis_lines;
y++)
+            memcpy( &p_dst[y * i_out_pitch], &p_src[y * i_pitch],
i_vis_pitch);
+
+        for (int32_t y = i_border_size_y ; y < i_vis_lines -
i_border_size_y; y++) {
+            memcpy( &p_dst[y * i_out_pitch], &p_src[y * i_pitch],
i_border_size_x);
+            memcpy( &p_dst[y * i_out_pitch + i_vis_pitch -
i_border_size_x], &p_src[y * i_pitch + i_vis_pitch - i_border_size_x],
i_border_size_x);
+        }
+    }
+
+}
+
+static void puzzle_draw_preview( filter_t *p_filter, picture_t *p_pic,
picture_t *p_pic_dst)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+
+    for( uint8_t  i_plane = 0; i_plane < p_pic_dst->i_planes; i_plane++ )
+    {
+        int32_t i_preview_offset = 0;
+        int32_t i_preview_size_x =
p_sys->ps_desk_planes[i_plane].i_visible_pitch *
p_sys->s_current_param.i_preview_size / 100;
+        int32_t i_preview_size_y =
p_sys->ps_desk_planes[i_plane].i_visible_lines *
p_sys->s_current_param.i_preview_size / 100;
+
+        const int32_t i_src_pitch    = p_pic->p[i_plane].i_pitch;
+        const int32_t i_dst_pitch    =
p_sys->ps_desk_planes[i_plane].i_pitch;
+
+        switch ( p_sys->i_preview_pos ) {
+        case 0:
+            i_preview_offset = 0;
+            break;
+        case 1:
+            i_preview_offset =
p_sys->ps_desk_planes[i_plane].i_visible_pitch - 1 - i_preview_size_x;
+            break;
+        case 2:
+            i_preview_offset =
+                p_sys->ps_desk_planes[i_plane].i_visible_pitch - 1 -
i_preview_size_x
+                + ((int32_t) (
p_sys->ps_desk_planes[i_plane].i_visible_lines - 1 - i_preview_size_y )) *
i_dst_pitch;
+            break;
+        case 3:
+            i_preview_offset = ((int32_t) (
p_sys->ps_desk_planes[i_plane].i_visible_lines - 1 - i_preview_size_y )) *
i_dst_pitch;
+            break;
+        default:
+            i_preview_offset = 0;
+            break;
+        }
+
+        uint8_t *p_src = p_pic->p[i_plane].p_pixels;
+        uint8_t *p_dst = p_pic_dst->p[i_plane].p_pixels;
+
+        for ( int32_t y = 0; y < i_preview_size_y; y++ )
+            for ( int32_t x = 0; x < i_preview_size_x; x++ )
+                p_dst[ y * i_dst_pitch + x + i_preview_offset ] =
+                    p_src[ ( y * 100 /
p_sys->s_current_param.i_preview_size ) * i_src_pitch + ( x * 100 /
p_sys->s_current_param.i_preview_size ) ];
+    }
+
+}
+
+static void puzzle_draw_pieces( filter_t *p_filter, picture_t *p_src_pic,
picture_t *p_dst_pic)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if ((p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL))
+        return;
+
+    for( uint8_t i_plane = 0; i_plane < p_dst_pic->i_planes; i_plane++ )
+    {
+        const int32_t i_src_pitch    = p_src_pic->p[i_plane].i_pitch;
+        const int32_t i_dst_pitch    = p_dst_pic->p[i_plane].i_pitch;
+        const int32_t i_src_visible_lines    =
p_src_pic->p[i_plane].i_visible_lines;
+        const int32_t i_dst_visible_lines    =
p_dst_pic->p[i_plane].i_visible_lines;
+        uint8_t *p_src = p_src_pic->p[i_plane].p_pixels;
+        uint8_t *p_dst = p_dst_pic->p[i_plane].p_pixels;
+
+        for ( int32_t i = p_sys->s_allocated.i_pieces_nbr-1; i >= 0 ; i-- )
+        {
+            piece_t *ps_piece = &p_sys->ps_pieces[i];
+
+            const int32_t i_desk_start_x =
ps_piece->ps_piece_in_plane[i_plane].i_actual_x;
+            const int32_t i_desk_start_y =
ps_piece->ps_piece_in_plane[i_plane].i_actual_y;
+            const int32_t i_pic_start_x =
ps_piece->ps_piece_in_plane[i_plane].i_original_x;
+            const int32_t i_pic_start_y =
ps_piece->ps_piece_in_plane[i_plane].i_original_y;
+            const int32_t i_size_x =
ps_piece->ps_piece_in_plane[i_plane].i_size_x;
+            const int32_t i_size_y =
ps_piece->ps_piece_in_plane[i_plane].i_size_y;
+
+            if (!p_sys->s_current_param.b_advanced
+                    || (ps_piece->i_actual_mirror == 1 &&
ps_piece->i_actual_angle == 0
+                    && p_sys->s_current_param.i_shape_size == 0))
+            {
+            // basic version rectangular & angle = 0
+                const int32_t i_ofs_x = MAX(0,
MAX(-i_desk_start_x,-i_pic_start_x));
+                const int32_t i_count_x = i_size_x - MAX(0,
MAX(i_desk_start_x + i_size_x - i_dst_pitch, i_pic_start_x + i_size_x -
i_src_pitch ));
+                const int32_t i_ofs_y = MAX(0,
MAX(-i_desk_start_y,-i_pic_start_y));
+                const int32_t i_count_y = i_size_y - MAX(0,
MAX(i_desk_start_y + i_size_y - i_dst_visible_lines, i_pic_start_y +
i_size_y - i_src_visible_lines ));
+
+                for (int32_t i_y = i_ofs_y; i_y < i_count_y; i_y++)
+                {
+                    memcpy( p_dst + (i_desk_start_y + i_y) * i_dst_pitch +
i_desk_start_x + i_ofs_x,
+                        p_src + (i_pic_start_y + i_y) * i_src_pitch +
i_pic_start_x + i_ofs_x,
+                        i_count_x - i_ofs_x);
+                }
+            }
+            else if ( ( p_sys->s_current_param.i_shape_size == 0)  ||
!p_sys->b_shape_init  || (p_sys->ps_pieces_shapes == NULL) ||
(!p_sys->b_shape_init) )
+            {
+            // here we still have rectangular shape but angle is not 0
+                for (int32_t i_y = 0; i_y < i_size_y; i_y++)
+                {
+                    int32_t i_current_src_y = i_pic_start_y + i_y;
+
+                    if ( ( i_current_src_y >= 0 ) && ( i_current_src_y <
i_src_visible_lines ) )
+                    {
+                        for (int32_t i_x = 0; i_x < i_size_x; i_x++)
+                        {
+                            int32_t i_current_dst_x = i_desk_start_x + i_x
* ps_piece->i_step_x_x + i_y * ps_piece->i_step_y_x;
+                            int32_t i_current_dst_y = i_desk_start_y + i_x
* ps_piece->i_step_x_y + i_y * ps_piece->i_step_y_y;
+                            int32_t i_current_src_x = i_pic_start_x + i_x;
+
+                            if ( ( i_current_dst_x  >= 0 ) && (
i_current_src_x >= 0 )
+                                    && ( i_current_dst_x  < i_dst_pitch )
&& ( i_current_src_x < i_src_pitch )
+                                    && ( i_current_dst_y >= 0 ) && (
i_current_dst_y < i_dst_visible_lines ) )
+                            {
+                                p_dst[ i_current_dst_y * i_dst_pitch +
i_current_dst_x ] =
+                                    p_src[ i_current_src_y * i_src_pitch +
i_current_src_x ];
+                            }
+                        }
+                    }
+                }
+            }
+            else
+            {
+            // "puzzle" shape and maybe angle != 0
+                piece_shape_t *ps_top_shape =
&p_sys->ps_pieces_shapes[ps_piece->i_top_shape][i_plane];
+                piece_shape_t *ps_btm_shape =
&p_sys->ps_pieces_shapes[ps_piece->i_btm_shape][i_plane];
+                piece_shape_t *ps_right_shape =
&p_sys->ps_pieces_shapes[ps_piece->i_right_shape][i_plane];
+                piece_shape_t *ps_left_shape =
&p_sys->ps_pieces_shapes[ps_piece->i_left_shape][i_plane];
+                piece_shape_t *ps_shape;
+
+                int32_t i_min_y = ps_top_shape->i_first_row_offset;
+                int32_t i_max_y = ps_btm_shape->i_first_row_offset +
ps_btm_shape->i_row_nbr - 1;
+
+                for (int32_t i_y = i_min_y; i_y <= i_max_y; i_y++)
+                {
+                    int32_t i_current_src_y = i_pic_start_y + i_y;
+
+                    if ( ( i_current_src_y >= 0 ) && ( i_current_src_y <
i_src_visible_lines ) )
+                    {
+                        int32_t i_sect_start_x = 0;
+
+                        //process each sub shape (each quarter):
+                        for (int8_t i_shape=0; i_shape < 4; i_shape++)
+                        {
+                            switch ( i_shape )
+                            {
+                              case 0:
+                                ps_shape = ps_left_shape;
+                                break;
+                              case 1:
+                                ps_shape = ps_top_shape;
+                                break;
+                              case 2:
+                                ps_shape = ps_btm_shape;
+                                break;
+                              case 3:
+                                ps_shape = ps_right_shape;
+                                break;
+                            }
+
+                            int32_t i_r = i_y -
ps_shape->i_first_row_offset;
+
+                            if (i_r >=0 && i_r < ps_shape->i_row_nbr)
+                            {
+                                piece_shape_row_t *ps_piece_shape_row =
&ps_shape->ps_piece_shape_row[i_r];
+
+                                for (int32_t i_s = 0; i_s <
ps_piece_shape_row->i_section_nbr; i_s++)
+                                {
+                                    uint8_t i_type =
ps_piece_shape_row->ps_row_section[i_s].i_type;
+                                    int32_t i_width =
ps_piece_shape_row->ps_row_section[i_s].i_width;
+                                    if (i_type == 0)
+                                    {
+                                        // fill
+                                        for (int32_t i_x = 0; i_x <
i_width; i_x++)
+                                        {
+                                            int32_t i_current_dst_x =
i_desk_start_x + (i_sect_start_x + i_x) * ps_piece->i_step_x_x + i_y *
ps_piece->i_step_y_x;
+                                            int32_t i_current_dst_y =
i_desk_start_y + (i_sect_start_x + i_x) * ps_piece->i_step_x_y + i_y *
ps_piece->i_step_y_y;
+                                            int32_t i_current_src_x =
i_pic_start_x + (i_sect_start_x + i_x);
+
+                                            if ( ( i_current_dst_x  >= 0 )
&& ( i_current_src_x >= 0 )
+                                                    && ( i_current_dst_x  <
i_dst_pitch ) && ( i_current_src_x < i_src_pitch )
+                                                    && ( i_current_dst_y >=
0 ) && ( i_current_dst_y < i_dst_visible_lines ) )
+                                            {
+                                                p_dst[ i_current_dst_y *
i_dst_pitch + i_current_dst_x ] =
+                                                    p_src[ i_current_src_y
* i_src_pitch + i_current_src_x ];
+                                                if (i_plane == 0)
+                                                {
+                                                    if (p_sys->i_mouse_x ==
i_current_dst_x )
+                                                    {
+                                                        if
(p_sys->i_mouse_y == i_current_dst_y )
+
p_sys->i_pointed_pce = i;
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                    i_sect_start_x += i_width;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    return;
+}
+
+static void draw_sign(picture_t *p_pic_dst, int32_t i_x, int32_t i_y,
int32_t i_size_x, int32_t i_size_y, const char **ppsz_sign, bool b_reverse)
+{
+    plane_t *p_out = &p_pic_dst->p[Y_PLANE];
+    uint8_t i_Y;
+
+    i_Y = ( p_out->p_pixels[ i_y * p_out->i_pitch + i_x ] >= 0x7F ) ? 0x00
: 0xFF;
+
+    for( int32_t i = 0; i < i_size_y ; i++ )
+        for( int32_t j = 0; j < i_size_x; j++ )
+        {
+            int32_t i_dst_x = j + i_x;
+            int32_t i_dst_y = i + i_y;
+            if ( ppsz_sign[i][b_reverse?i_size_x-1-j:j] == 'o' )
+            {
+                if ((i_dst_x < p_out->i_visible_pitch) && (i_dst_y <
p_out->i_visible_lines) && (i_dst_x >= 0 ) && (i_dst_y >= 0))
+                {
+                    p_out->p_pixels[ i_dst_y * p_out->i_pitch + i_dst_x ] =
i_Y;
+                }
+            }
+            else if ( ppsz_sign[i][b_reverse?i_size_x-1-j:j] == '.' )
+            {
+                if ((i_dst_x < p_out->i_visible_pitch) && (i_dst_y <
p_out->i_visible_lines) && (i_dst_x >= 0 ) && (i_dst_y >= 0))
+                {
+                    p_out->p_pixels[ i_dst_y * p_out->i_pitch + i_dst_x ] =
p_out->p_pixels[ i_dst_y * p_out->i_pitch + i_dst_x ] / 2 + i_Y / 2;
+                }
+            }
+        }
+}
+
+static void draw_rectangle(picture_t *p_pic_dst, int32_t i_x, int32_t i_y,
int32_t i_w, int32_t i_h, uint8_t i_Y, uint8_t i_U, uint8_t i_V )
+{
+    uint8_t i_c;
+
+    for( uint8_t i_plane = 0; i_plane < p_pic_dst->i_planes; i_plane++ ) {
+        plane_t *p_oyp = &p_pic_dst->p[i_plane];
+
+        if (i_plane == Y_PLANE)
+            i_c = i_Y;
+        else if (i_plane == U_PLANE)
+            i_c = i_U;
+        else if (i_plane == V_PLANE)
+            i_c = i_V;
+
+        int32_t i_x_min = i_x * p_oyp->i_visible_pitch /
p_pic_dst->p[0].i_visible_pitch;
+        int32_t i_x_max = (i_x + i_w) * p_oyp->i_visible_pitch /
p_pic_dst->p[0].i_visible_pitch;
+        int32_t i_y_min = i_y * p_oyp->i_visible_lines /
p_pic_dst->p[0].i_visible_lines;
+        int32_t i_y_max = (i_y + i_h) * p_oyp->i_visible_lines
/p_pic_dst->p[0].i_visible_lines;
+
+        /* top line */
+        memset( &p_oyp->p_pixels[i_y_min * p_oyp->i_pitch + i_x_min], i_c,
i_x_max - i_x_min);
+
+        /* left and right */
+        for( int32_t i_dy = 1; i_dy < i_y_max - i_y_min - 1; i_dy++ ) {
+            p_oyp->p_pixels[(i_y_min + i_dy) * p_oyp->i_pitch + i_x_min ] =
i_c;
+            p_oyp->p_pixels[(i_y_min + i_dy) * p_oyp->i_pitch + i_x_max -
1] = i_c;
+        }
+
+        /* bottom line */
+        memset( &p_oyp->p_pixels[(i_y_max - 1) * p_oyp->i_pitch + i_x_min],
i_c,  i_x_max - i_x_min);
+    }
+}
+
+static void fill_rectangle(picture_t *p_pic_dst, int32_t i_x, int32_t i_y,
int32_t i_w, int32_t i_h, uint8_t i_Y, uint8_t i_U, uint8_t i_V )
+{
+    uint8_t i_c;
+
+    for( uint8_t i_plane = 0; i_plane < p_pic_dst->i_planes; i_plane++ )
+    {
+        plane_t *p_oyp = &p_pic_dst->p[i_plane];
+
+        if (i_plane == Y_PLANE)
+            i_c = i_Y;
+        else if (i_plane == U_PLANE)
+            i_c = i_U;
+        else if (i_plane == V_PLANE)
+            i_c = i_V;
+
+        int32_t i_x_min = i_x * p_oyp->i_visible_pitch /
p_pic_dst->p[0].i_visible_pitch;
+        int32_t i_x_max = (i_x + i_w) * p_oyp->i_visible_pitch /
p_pic_dst->p[0].i_visible_pitch;
+        int32_t i_y_min = i_y * p_oyp->i_visible_lines /
p_pic_dst->p[0].i_visible_lines;
+        int32_t i_y_max = (i_y + i_h) * p_oyp->i_visible_lines
/p_pic_dst->p[0].i_visible_lines;
+
+        for( int32_t i_dy = 0; i_dy < i_y_max - i_y_min; i_dy++ )
+            memset( &p_oyp->p_pixels[(i_y_min + i_dy) * p_oyp->i_pitch +
i_x_min], i_c,  i_x_max - i_x_min);
+    }
+}
+
+static int32_t diagonal_limit( filter_t *p_filter, int32_t i_y, bool
b_left, uint8_t i_plane )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    if (b_left ^ (i_y >= p_sys->ps_desk_planes[i_plane].i_pieces_max_y /
2))
+        return ( i_y * p_sys->ps_desk_planes[i_plane].i_pieces_max_x) /
p_sys->ps_desk_planes[i_plane].i_pieces_max_y;
+    else
+        return p_sys->ps_desk_planes[i_plane].i_pieces_max_x - ( ( i_y *
p_sys->ps_desk_planes[i_plane].i_pieces_max_x) /
p_sys->ps_desk_planes[i_plane].i_pieces_max_y);
+
+}
+
+static point_t *scale_curve_H(int32_t i_size_x, int32_t i_size_y, uint8_t
i_pts_nbr, point_t *ps_pt, int32_t i_shape_size)
+{
+    if (ps_pt == NULL)
+        return NULL;
+
+    float f_x_ratio = ((float) i_size_x) / (1 - (-1));
+    float f_y_ratio = (((float)i_size_y) / 2) / (1 - (0));
+    float f_x_offset = ((float)i_size_x) / (1 - (-1));
+    float f_y_offset = 0;
+    float f_bez_x, f_bez_y;
+
+    float f_current_scale = 1;
+
+    uint8_t i_last_pt = (3 * (i_pts_nbr-1) + 1);
+
+    point_t *ps_new_pt = malloc( sizeof( point_t ) * i_last_pt );
+    if (ps_new_pt == NULL)
+        return NULL;
+
+    bool b_fit = true;
+
+    //check if the curve fit with available space:
+    do
+    {
+        b_fit = true;
+
+        for (uint8_t i_p = 0; i_p < i_last_pt; i_p++)
+        {
+            if ( i_p == 0 || i_p == 1 )
+            {
+                ps_new_pt[i_p].f_x = ps_pt[i_p].f_x * f_x_ratio +
f_x_offset;
+            }
+            else if ( i_p == i_last_pt - 2 || i_p == i_last_pt - 1 )
+            {
+                ps_new_pt[i_p].f_x = ps_pt[i_p].f_x * f_x_ratio +
f_x_offset;
+            }
+            else
+            {
+                ps_new_pt[i_p].f_x = ps_pt[i_p].f_x * f_x_ratio *
f_current_scale + f_x_offset;
+            }
+            ps_new_pt[i_p].f_y = ps_pt[i_p].f_y * f_y_ratio *
f_current_scale + f_y_offset;
+        }
+
+        for (float f_t = 0; f_t <= i_pts_nbr - 1; f_t += 0.1 )
+        {
+            int8_t i_main_t = floor(f_t);
+            if ( i_main_t == i_pts_nbr - 1 )
+                i_main_t = i_pts_nbr - 2;
+            float f_sub_t = f_t - i_main_t;
+
+            f_bez_x = ( 1 - f_sub_t ) * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_new_pt[ 3 * i_main_t ].f_x
+                    + 3 * f_sub_t * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_new_pt[ 3 * i_main_t + 1 ].f_x
+                    + 3 * f_sub_t * f_sub_t * ( 1 - f_sub_t ) * ps_new_pt[
3 * i_main_t + 2 ].f_x
+                    + f_sub_t * f_sub_t * f_sub_t * ps_new_pt[ 3 * i_main_t
+ 3 ].f_x;
+
+            f_bez_y = ( 1 - f_sub_t ) * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_new_pt[ 3 * i_main_t ].f_y
+                    + 3 * f_sub_t * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_new_pt[ 3 * i_main_t + 1 ].f_y
+                    + 3 * f_sub_t * f_sub_t * ( 1 - f_sub_t ) * ps_new_pt[
3 * i_main_t + 2 ].f_y
+                    + f_sub_t * f_sub_t * f_sub_t * ps_new_pt[ 3 * i_main_t
+ 3 ].f_y;
+
+            if ( f_bez_x < ((float) i_size_x) / 2 )
+            {
+                if ( abs ( f_bez_y ) > ( f_bez_x * ( 0.9 *
((float)i_size_y) / ((float)i_size_x) ) ) )
+                {
+                    b_fit = false;
+                }
+            }
+            else
+            {
+                if ( abs ( f_bez_y ) > ( ( ((float)i_size_x) - f_bez_x ) *
( 0.9 * ((float)i_size_y) / ((float)i_size_x) ) ) )
+                {
+                    b_fit = false;
+                }
+            }
+        }
+
+        if (!b_fit)
+        {
+            f_current_scale = f_current_scale * 0.9;
+        }
+
+    }
+    while ((!b_fit) && (f_current_scale>0.1));
+
+    if (!b_fit)
+    {
+        free(ps_new_pt);
+        ps_new_pt = NULL;
+    }
+
+    // global scale shall be applied:
+    f_current_scale = f_current_scale * (0.5 + 0.5* (float)i_shape_size /
100);
+    for (uint8_t i_p = 0; i_p < i_last_pt; i_p++)
+    {
+        if ( i_p == 0 || i_p == 1 )
+        {
+            ps_new_pt[i_p].f_x = ps_pt[i_p].f_x * f_x_ratio + f_x_offset;
+        }
+        else if ( i_p == i_last_pt - 2 || i_p == i_last_pt - 1 )
+        {
+            ps_new_pt[i_p].f_x = ps_pt[i_p].f_x * f_x_ratio + f_x_offset;
+        }
+        else
+        {
+            ps_new_pt[i_p].f_x = ps_pt[i_p].f_x * f_x_ratio *
f_current_scale + f_x_offset;
+        }
+        ps_new_pt[i_p].f_y = ps_pt[i_p].f_y * f_y_ratio * f_current_scale +
f_y_offset;
+    }
+
+
+    return ps_new_pt;
+}
+
+static point_t *H_2_scale_curve_V(int32_t i_size_x, int32_t i_size_y,
uint8_t i_pts_nbr, point_t *ps_pt, int32_t i_shape_size)
+{
+    if (ps_pt == NULL)
+        return NULL;
+
+    point_t *ps_bezier_scale_H = scale_curve_H(i_size_y, i_size_x,
i_pts_nbr, ps_pt, i_shape_size);
+    point_t *ps_pts_V = curve_H_2_V(i_pts_nbr, ps_bezier_scale_H);
+    free(ps_bezier_scale_H);
+
+    return ps_pts_V;
+}
+
+static point_t *curve_H_2_V(uint8_t i_pts_nbr, point_t *ps_pt)
+{
+    if (ps_pt == NULL)
+        return NULL;
+
+    point_t *ps_new_pt = malloc( sizeof( point_t ) * (3 * (i_pts_nbr-1) +
1) );
+
+    if (ps_new_pt == NULL)
+        return NULL;
+
+    for (uint8_t i=0; i < (3 * (i_pts_nbr-1) + 1); i++)
+    {
+        ps_new_pt[i].f_x = ps_pt[i].f_y;
+        ps_new_pt[i].f_y = ps_pt[i].f_x;
+    }
+
+    return ps_new_pt;
+}
+
+static point_t *curve_H_2_negative(uint8_t i_pts_nbr, point_t *ps_pt)
+{
+    if (ps_pt == NULL)
+        return NULL;
+
+    point_t *ps_new_pt = malloc( sizeof( point_t ) * (3 * (i_pts_nbr-1) +
1) );
+    if (ps_new_pt == NULL)
+        return NULL;
+
+    for (uint8_t i=0; i < (3 * (i_pts_nbr-1) + 1); i++)
+    {
+        ps_new_pt[i].f_x = ps_pt[i].f_x;
+        ps_new_pt[i].f_y = -ps_pt[i].f_y;
+    }
+
+    return ps_new_pt;
+}
+
+static point_t *curve_V_2_negative(uint8_t i_pts_nbr, point_t *ps_pt)
+{
+    if (ps_pt == NULL)
+        return NULL;
+
+    point_t *ps_new_pt = malloc( sizeof( point_t ) * (3 * (i_pts_nbr-1) +
1) );
+    if (ps_new_pt == NULL)
+        return NULL;
+
+    for (uint8_t i=0; i < (3 * (i_pts_nbr-1) + 1); i++)
+    {
+        ps_new_pt[i].f_x = -ps_pt[i].f_x;
+        ps_new_pt[i].f_y = ps_pt[i].f_y;
+    }
+
+    return ps_new_pt;
+}
+
+static point_t *rand_bezier(uint8_t i_pts_nbr)
+{
+#define NB_PRIM 13
+    point_t ps_pt[NB_PRIM][19] = {  {{ -1,    0}, { -0.708333333333333,
0},
+                               {  -0.375,    -0.333333333333333}, {
-0.166666666666667,    0.0833333333333333}, { -0.0833333333333334,
0.208333333333333},
+                               { -0.375,    0.416666666666667}, { -0.4,
0.583333333333333}, { -0.416666666666667,    0.833333333333333},
+                               { -0.25,    1}, { 0,    1}, { 0.25,    1},
+                               { 0.416666666666667,    0.833333333333333},
{ 0.4,    0.583333333333333}, { 0.375,    0.416666666666667},
+                               { 0.0833333333333334,    0.208333333333333},
{ 0.166666666666667,    0.0833333333333333}, { 0.375,
-0.333333333333333},
+                               {  0.708333333333333,    0}, { 1,    0}},
+
+                               {{ -1,    0}, { -0.708231074018077,
0.00464090724581488},
+                               {  -0.323236452068492,
-0.372786060362316}, { -0.116455168200171,    0.044302770499351}, {
-0.0335691043909019,    0.211488362938889},
+                               { -0.437927544463254,    0.38719460194857},
{ -0.465325829944998,    0.551293871552922}, { -0.483454564038933,
0.65987409733561},
+                               { -0.190232837055291,    0.93567381392124},
{ 0.0642797691187335,    0.936855546259066}, {0.313367868665637,
0.938012091966671},
+                               {0.487146524283283,   0.816195130161918},
{0.469545566313243,   0.564387421486367}, {0.446892478470506,
0.24030153060388},
+                               {0.207135456718658,   0.246041323358689},
{0.287851875888374,   0.122157561245575}, {0.492785457693622,
-0.19237501290106},
+                               { 0.707786879710212,
0.000871347032899226}, {1,   0}},
+
+                               {{ -1,    0}, { -0.704537606957651,
0.00470344095405053},
+                               {  -0.435930692234854,
-0.352359270526667}, { -0.228149843936683,    0.0679948519756222}, {
-0.146863413857337,    0.232442568245956},
+                               { -0.400774053301818,    0.353459760810654},
{ -0.422294600163745,    0.522585095895632}, { -0.436816721748459,
0.636711316521778},
+                               { -0.139151386987432,    1.08020929564109},
{ 0.110882572064929,    1.08261729027387}, {0.36153850539327,
1.08503127493587},
+                               {0.34588115345217,   0.865990116291394},
{0.329903557511847,   0.612892723601664}, {0.308148644342904,
0.26827818823501},
+                               {0.127493141873546,   0.13002329074962},
{0.214157995034913,   0.0010516930680228}, {0.419298604696494,
-0.304231373969182},
+                               { 0.710915592189813,
-0.00442574861414977}, {1,   0}},
+
+                               {{ -1,    0}, { -0.712310641244798,
-0.00176730760415818},
+                               {  -0.493540738434648,
-0.309260977632173}, { -0.285884861158849,    0.102814242456153}, {
-0.204387117876255,    0.264539501285563},
+                               { -0.420693738052021,    0.397849004532357},
{ -0.441431505287778,    0.562611714939519}, { -0.461628378308195,
0.723076990818189},
+                               { -0.237390284827422,    0.937205665156549},
{ 0.012635296180645,    0.941029970697368}, {0.262998571390198,
0.94485944149288},
+                               {0.388416614305901,   0.85661645417048},
{0.371248440058972,   0.611257540385605}, {0.345208629600827,
0.239109662732447},
+                               {0.0581354739284663,   0.176880217503811},
{0.136998743377185,   0.0517079719473858}, {0.348267592311711,
-0.283619188873049},
+                               { 0.708090161530147,
0.000345266964160967}, {1,   0}},
+
+                               {{ -1,    0}, { -0.711243094744545,
-0.00459592941542872},
+                               {  -0.344045254972826,
-0.249350550360079}, { -0.133712969208732,    0.170729185550043}, {
-0.0464161071620253,    0.345080177938788},
+                               { -0.422103631801675,    0.334575981154338},
{ -0.450380528566562,    0.498555760394576}, { -0.467099640727027,
0.595511106801977},
+                               { -0.207078052226595,    0.975846125373965},
{ 0.042159574981007,    0.973462055639965}, {0.287191021206139,
0.971118219914322},
+                               {0.330852515542335,   0.808592956913444},
{0.310390322812144,   0.55585802623889}, {0.283433878730578,
0.222910569628582},
+                               {0.164262943948071,   0.173598366742734},
{0.251741291720702,   0.049453960261478}, {0.457341230249114,
-0.24232203906962},
+                               { 0.708383662881845,   0.00453591968074395},
{1,   0}},
+
+                               {{ -1,    0}, { -0.709563566764519,
0.000504612933340335},
+                               {  -0.401784990268149,
-0.401999124062464}, { -0.193592021826356,    0.0146187796927396}, {
-0.111906932669809,    0.178079970851903},
+                               { -0.31875772800715,    0.350308507939804},
{ -0.348317101378293,    0.519642874263023}, { -0.364751907373417,
0.613791604139223},
+                               { -0.261109769059908,    0.917602975781519},
{ -0.0140971269841824,    0.920487199482641}, {0.239116574515885,
0.923443829366756},
+                               {0.464370661288271,   0.826483978760365},
{0.447638420230199,   0.579781906213412}, {0.422345781938457,
0.206864359478527},
+                               {0.125463036793575,   0.196073913812856},
{0.210079852894537,   0.0665488867084866}, {0.418467910269307,
-0.25243580242811},
+                               { 0.703900021885974,   0.00330911444674605},
{1,   0}},
+
+                               {{ -1,    0}, { -0.705550924110721,
0.00312677407583926},
+                               {  -0.415041079490389,
-0.256262603613135}, { -0.206251758814373,    0.165228519752475}, {
-0.127460686840124,    0.324287121648782},
+                               { -0.353486555975517,    0.448219649272319},
{ -0.374301593332884,    0.615673871700604}, { -0.394013085772568,
0.774250221227079},
+                               { -0.28341474824943,    1.03226208905838}, {
-0.0332682368974526,    1.03258310507818}, {0.21500235815775,
1.03290171371209},
+                               {0.359673321091526,   0.870921326239785},
{0.339932613238046,   0.624982013252291}, {0.312186121753393,
0.279302764858672},
+                               {0.115889225615101,   0.23413749518865},
{0.199563649684811,   0.112671061164123}, {0.404949947429742,
-0.185479078044395},
+                               { 0.711077310890697,
-0.00496397607736578}, {1,   0}},
+
+                               {{ -1,    0}, { -0.703393023950601,
0.00477096251262726},
+                               {  -0.397655885794691,
-0.396549402674607}, { -0.188941722741602,    0.0154382717692692}, {
-0.108388702754651,    0.174444497740687},
+                               { -0.373390092271521,    0.482883861046198},
{ -0.40085845720332,    0.649893787354158}, { -0.415216707820891,
0.73719313638733},
+                               { -0.207371750103189,    0.945376369116883},
{ 0.0450859051405016,    0.945770549381538}, {0.295681992651987,
0.946161823046823},
+                               {0.436428045351514,   0.895032817250379},
{0.416214840162102,   0.640148265397975}, {0.392784984133714,
0.344702377534045},
+                               {0.112552686103251,   0.228040049100136},
{0.197835182813393,   0.100734153702732}, {0.405083123585628,
-0.208636299638369},
+                               { 0.710532321943806,   0.00118461271792703},
{1,   0}},
+
+                               {{ -1,    0}, { -0.708545258498605,
-0.00125649641636185},
+                               {  -0.337498620726249,
-0.244893936731276}, { -0.124910631945282,    0.17201407250253}, {
-0.0378099534640198,    0.342827911406433},
+                               { -0.388593443990334,    0.484174318751186},
{ -0.418161094500799,    0.649198946145559}, { -0.437373248647437,
0.756426897124284},
+                               { -0.189109020838902,    0.919750563663455},
{ 0.0617320119458061,    0.92141119323056}, {0.31608889374516,
0.923095098586168},
+                               {0.498311890876136,   0.848907293614162},
{0.486010157001842,   0.596632149071449}, {0.461260133020122,
0.0890763897591911},
+                               {0.075676233826577,   0.15314863012444},
{0.155893607369245,   0.0261168678327565}, {0.366248653274704,
-0.307000149194794},
+                               { 0.711164480468843,   0.00394203362859574},
{1,   0}},
+
+                               {{ -1,    0}, { -0.707183721193905,
0.00108263364450203},
+                               {  -0.483784802307194,
-0.278675576139177}, { -0.276928949597787,    0.142419327760986}, {
-0.193170452053892,    0.312925871385917},
+                               { -0.451215340488792,    0.477259970702323},
{ -0.47460300367851,    0.643765731024187}, { -0.494031809431451,
0.782086864170215},
+                               { -0.236790915210626,    0.959374429536679},
{ 0.0132927154237516,    0.955639549881874}, {0.267150847268955,
0.951848299853113},
+                               {0.394360682972295,   0.847565361471232},
{0.378470732344786,   0.601630247482969}, {0.354536849929646,
0.231195987620713},
+                               {0.0517827835992971,   0.214030018332778},
{0.131796334571256,   0.0912722226051247}, {0.336621017220957,
-0.222972380306016},
+                               { 0.703679022364791,
-0.00331356185794636}, {1,   0}},
+
+                               {{ -1,    0}, { -0.71248840208346,
-0.000315316402810925},
+                               {  -0.335615004340797,
-0.24819255482402}, { -0.131187942697538,    0.164054053482729}, {
-0.0493962500017139,    0.3289947791894},
+                               { -0.419381248020232,    0.390159881019368},
{ -0.441651048160997,    0.558451191050566}, { -0.455822752006908,
0.665545758156122},
+                               { -0.233491027161151,    0.962685238392525},
{ 0.0133445688612305,    0.95860585518251}, {0.262151404887793,
0.954493893837471},
+                               {0.353774477399895,   0.909561597589476},
{0.33709535778317,   0.660905314411181}, {0.31704981166686,
0.362061544110332},
+                               {0.105412252277536,   0.191206346512902},
{0.186218651070473,   0.0649153599195794}, {0.398293919310497,
-0.266533575537957},
+                               { 0.704071013216639,   0.00309631694609307},
{1,   0}},
+
+                               {{ -1,    0}, { -0.705056079463317,
0.00448211481221729},
+                               {  -0.436957920272407,
-0.370262236529651}, { -0.229712063674328,    0.0431705143488563}, {
-0.148227797168837,    0.205722687925072},
+                               { -0.393257971601542,    0.424195267916701},
{ -0.413510880163265,    0.589027317989955}, { -0.431898814144998,
0.738680926783159},
+                               { -0.283603628196569,    0.915912313032585},
{ -0.0357952161759055,    0.912250885919817}, {0.219122757016883,
0.908484413381742},
+                               {0.443769349276008,   0.835076661704473},
{0.426106787792343,   0.583529647320461}, {0.400589787646949,
0.220121134430258},
+                               {0.160593774137044,   0.15625323679053},
{0.245514983733696,   0.0314675787386357}, {0.452432214072397,
-0.272582526914925},
+                               { 0.707859045957901,
-0.00364987569003833}, {1,   0}},
+
+                               { { -1,    0}, { -0.707920686483174,
0.00318900911649754},
+                               {  -0.434372174464315,
-0.307446433658587}, { -0.22207624254243,    0.109425261995917}, {
-0.137453117820789,    0.275594180895755},
+                               { -0.340508174095858,    0.364631782467402},
{ -0.369080584284576,    0.527714098008385}, { -0.383671882476694,
0.610996631060469},
+                               { -0.233753076988816,    0.939761357928644},
{ 0.0204626018463874,    0.936196353095824}, {0.268226367774715,
0.932721826949446},
+                               {0.500766516589953,   0.908734435247741},
{0.488915515020803,   0.659928459184412}, {0.468202989215343,
0.225079120105809},
+                               {0.106186153956061,   0.298643666003939},
{0.184680334657865,   0.170455849778656}, {0.39345790442032,
-0.1704960590812},
+                               { 0.713223372514099,
-0.000707944210808817}, {1,   0}}
+                               };
+
+    if (i_pts_nbr != 7)
+        return NULL;
+
+//random shape
+    uint8_t i_last_pt = (3 * (i_pts_nbr-1) + 1);
+    uint8_t i_item = ((uint16_t) vlc_mrand48()) %  NB_PRIM;
+
+    point_t *ps_new_pt = malloc( sizeof( point_t ) * i_last_pt );
+    if (ps_new_pt == NULL)
+        return NULL;
+
+    if ((vlc_mrand48() & 1) == 1)
+        for (uint8_t i=0; i < i_last_pt; i++)
+        {
+            ps_new_pt[i].f_x = ps_pt[i_item][i].f_x;
+            ps_new_pt[i].f_y = ps_pt[i_item][i].f_y;
+        }
+    else
+        for (uint8_t i=0; i < i_last_pt; i++)
+        {
+            ps_new_pt[i].f_x = ps_pt[i_item][i_last_pt-1-i].f_x;
+            ps_new_pt[i].f_y = ps_pt[i_item][i_last_pt-1-i].f_y;
+        }
+
+//random shape size
+    float f_current_scale = 0.7 + ( (float) (vlc_mrand48() %  1001 ) / 1000
)*0.3;
+    for (uint8_t i_p = 0; i_p < i_last_pt; i_p++)
+    {
+        if ( i_p != 0 && i_p != 1 && i_p != i_last_pt - 2 && i_p !=
i_last_pt - 1 )
+        {
+            ps_new_pt[i_p].f_x = ps_new_pt[i_p].f_x * f_current_scale;
+        }
+        ps_new_pt[i_p].f_y = ps_new_pt[i_p].f_y * f_current_scale;
+    }
+
+//random shape shift
+    float f_offset = ( ( (float) (vlc_mrand48() %  1001 ) / 1000 ) - 0.5 )
* 0.2;
+    for (uint8_t i=1; i < i_pts_nbr - 1; i++)
+    {
+        ps_new_pt[i*3-1].f_x += f_offset;
+        ps_new_pt[i*3].f_x += f_offset;
+        ps_new_pt[i*3+1].f_x += f_offset;
+    }
+
+    return ps_new_pt;
+}
+
+#define MAX_SECT 10
+
+static void generate_sectTopB( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_plane)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    int32_t i_size_y = p_sys->ps_desk_planes[i_plane].i_pieces_max_y;
+
+// first: get min y:
+    float f_min_curve_y = 0;
+
+//next: process each horizontal pixel lines:
+    int32_t i_min_y =floor(f_min_curve_y);
+    int32_t i_nb_y = i_size_y /2 - i_min_y;
+
+// allocate memory
+    ps_piece_shape->i_row_nbr = i_nb_y;
+    ps_piece_shape->i_first_row_offset = i_min_y;
+    ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t
) * i_nb_y );
+
+    for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++)
+    {
+        uint8_t i_sect = 0;
+        int32_t pi_sects[MAX_SECT];
+        int32_t i_row = i_y - i_min_y;
+
+// ...fill from border to next junction
+        pi_sects[i_sect] = diagonal_limit( p_filter, i_y, false, i_plane )
- 1 - (diagonal_limit( p_filter, i_y, true, i_plane ) - 1);
+        i_sect++;
+
+// ...allocate memory and copy final values
+        ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
+        ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_sect);
+        for (uint8_t i=0; i < i_sect; i++)
+        {
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = i % 2;
// 0 = fill ; 1 = offset
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+        }
+
+    }
+}
+
+static void generate_sectLeftB( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_plane)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    int32_t i_size_y = p_sys->ps_desk_planes[i_plane].i_pieces_max_y;
+
+// first: get min y:
+    float f_min_curve_y = 0;
+
+//next: process each horizontal pixel lines:
+    int32_t i_min_y =floor(f_min_curve_y);
+    int32_t i_nb_y = i_size_y - i_min_y;
+
+// allocate memory
+    ps_piece_shape->i_row_nbr = i_nb_y;
+    ps_piece_shape->i_first_row_offset = i_min_y;
+    ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t
) * i_nb_y );
+
+    for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++)
+    {
+        uint8_t i_sect = 0;
+        int32_t pi_sects[MAX_SECT];
+        int32_t i_row = i_y - i_min_y;
+
+// ...fill from border to next junction
+        pi_sects[i_sect] = diagonal_limit( p_filter, i_y, true, i_plane  );
+        i_sect++;
+
+// ...allocate memory and copy final values
+        ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
+        ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_sect);
+        for (uint8_t i=0; i < i_sect; i++)
+        {
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = i % 2;
// 0 = fill ; 1 = offset
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+        }
+
+    }
+}
+
+static void generate_sectRightB( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_plane)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    int32_t i_size_x = p_sys->ps_desk_planes[i_plane].i_pieces_max_x;
+    int32_t i_size_y = p_sys->ps_desk_planes[i_plane].i_pieces_max_y;
+
+// first: get min y:
+    float f_min_curve_y = 0;
+
+//next: process each horizontal pixel lines:
+    int32_t i_min_y =floor(f_min_curve_y);
+    int32_t i_nb_y = i_size_y - i_min_y;
+
+// allocate memory
+    ps_piece_shape->i_row_nbr = i_nb_y;
+    ps_piece_shape->i_first_row_offset = i_min_y;
+    ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t
) * i_nb_y );
+
+    for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++)
+    {
+        uint8_t i_sect = 0;
+        int32_t pi_sects[MAX_SECT];
+        int32_t i_row = i_y - i_min_y;
+
+// ...fill from border to next junction
+        pi_sects[i_sect] = i_size_x - diagonal_limit( p_filter, i_y, false,
i_plane );
+        i_sect++;
+
+// ...allocate memory and copy final values
+        ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
+        ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_sect);
+        for (uint8_t i=0; i < i_sect; i++)
+        {
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = i % 2;
// 0 = fill ; 1 = offset
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+        }
+
+    }
+}
+
+static void generate_sectBtmB( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_plane)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    int32_t i_size_y = p_sys->ps_desk_planes[i_plane].i_pieces_max_y;
+
+// first: get min y:
+    float f_min_curve_y = i_size_y / 2;
+
+//next: process each horizontal pixel lines:
+    int32_t i_min_y =floor(f_min_curve_y);
+    int32_t i_nb_y = i_size_y - i_min_y;
+
+// allocate memory
+    ps_piece_shape->i_row_nbr = i_nb_y;
+    ps_piece_shape->i_first_row_offset = i_min_y;
+    ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t
) * i_nb_y );
+
+    for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++)
+    {
+        uint8_t i_sect = 0;
+        int32_t pi_sects[MAX_SECT];
+        int32_t i_row = i_y - i_min_y;
+
+// ...fill from border to next junction
+        pi_sects[i_sect] = diagonal_limit( p_filter, i_y, false, i_plane )
- 1 - (diagonal_limit( p_filter, i_y, true, i_plane ) - 1);
+        i_sect++;
+
+// ...allocate memory and copy final values
+        ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
+        ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_sect);
+        for (uint8_t i=0; i < i_sect; i++)
+        {
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = i % 2;
// 0 = fill ; 1 = offset
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+        }
+
+    }
+}
+
+static void generate_sectTop( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_pts_nbr, point_t *ps_pt, uint8_t i_plane)
+{
+    if (ps_pt == NULL)
+    {
+        generate_sectTopB( p_filter, ps_piece_shape, i_plane);
+        return;
+    }
+
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    int32_t i_size_x = p_sys->ps_desk_planes[i_plane].i_pieces_max_x;
+    int32_t i_size_y = p_sys->ps_desk_planes[i_plane].i_pieces_max_y;
+
+    int32_t i_size_x_0 = p_sys->ps_desk_planes[0].i_pieces_max_x;
+    int32_t i_size_y_0 = p_sys->ps_desk_planes[0].i_pieces_max_y;
+
+    float f_x_ratio =  ((float) i_size_x) / ((float) i_size_x_0);
+    float f_y_ratio = ((float) i_size_y) / ((float) i_size_y_0);
+    float f_x_offset = 0;
+    float f_y_offset = 0;
+    float f_bez_x, f_bez_y;
+    float f_xo, f_yo, f_xd, f_yd;
+
+// first: get min y:
+    float f_min_curve_y = ps_pt[0].f_y * f_y_ratio + f_y_offset;
+
+    for (float f_t = 0; f_t <= i_pts_nbr - 1; f_t += 0.1 )
+    {
+        int8_t i_main_t = floor(f_t);
+        if ( i_main_t == i_pts_nbr - 1 )
+            i_main_t = i_pts_nbr - 2;
+        float f_sub_t = f_t - i_main_t;
+
+        f_bez_y = ( 1 - f_sub_t ) * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_pt[ 3 * i_main_t ].f_y
+                + 3 * f_sub_t * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) * ps_pt[
3 * i_main_t + 1 ].f_y
+                + 3 * f_sub_t * f_sub_t * ( 1 - f_sub_t ) * ps_pt[ 3 *
i_main_t + 2 ].f_y
+                + f_sub_t * f_sub_t * f_sub_t * ps_pt[ 3 * i_main_t + 3
].f_y;
+
+        f_yd = f_bez_y * f_y_ratio + f_y_offset;
+
+        if (f_yd < f_min_curve_y)
+            f_min_curve_y = f_yd;
+    }
+    f_min_curve_y = floor(f_min_curve_y);
+    if (f_min_curve_y > 0)
+        f_min_curve_y = 0;
+
+// next: process each horizontal pixel lines:
+    int32_t i_min_y = floor(f_min_curve_y);
+    int32_t i_nb_y = i_size_y / 2 - i_min_y;
+
+// allocate memory
+    ps_piece_shape->i_row_nbr = i_nb_y;
+    ps_piece_shape->i_first_row_offset = i_min_y;
+    ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t
) * ps_piece_shape->i_row_nbr );
+
+    for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++)
+    {
+        int32_t i_row = i_y - i_min_y;
+
+        uint8_t i_sect = 0;
+        int32_t pi_sects[MAX_SECT];
+
+// ...detect curve
+        int8_t i_main_t = 0;
+        f_xo = ps_pt[0].f_x * f_x_ratio + f_x_offset;
+        f_yo = ps_pt[0].f_y * f_y_ratio + f_y_offset;
+
+        for (float f_t = 0; f_t <= i_pts_nbr - 1; f_t += 0.1 )
+        {
+            i_main_t = floor(f_t);
+            if ( i_main_t == i_pts_nbr - 1 )
+                i_main_t = i_pts_nbr - 2;
+            float f_sub_t = f_t - i_main_t;
+
+            f_bez_x = ( 1 - f_sub_t ) * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_pt[ 3 * i_main_t ].f_x
+                    + 3 * f_sub_t * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_pt[ 3 * i_main_t + 1 ].f_x
+                    + 3 * f_sub_t * f_sub_t * ( 1 - f_sub_t ) * ps_pt[ 3 *
i_main_t + 2 ].f_x
+                    + f_sub_t * f_sub_t * f_sub_t * ps_pt[ 3 * i_main_t + 3
].f_x;
+
+            f_bez_y = ( 1 - f_sub_t ) * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_pt[ 3 * i_main_t ].f_y
+                    + 3 * f_sub_t * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_pt[ 3 * i_main_t + 1 ].f_y
+                    + 3 * f_sub_t * f_sub_t * ( 1 - f_sub_t ) * ps_pt[ 3 *
i_main_t + 2 ].f_y
+                    + f_sub_t * f_sub_t * f_sub_t * ps_pt[ 3 * i_main_t + 3
].f_y;
+
+            f_xd = f_bez_x * f_x_ratio + f_x_offset;
+            f_yd = f_bez_y * f_y_ratio + f_y_offset;
+
+            if ((f_yo < (float)i_y+0.5 && f_yd >= (float)i_y+0.5) || (f_yo
> (float)i_y+0.5 && f_yd <= (float)i_y+0.5))
+            {
+                pi_sects[i_sect] = floor(((float)i_y+0.5 - f_yo) * (f_xd -
f_xo) / (f_yd - f_yo) + f_xo);
+                if (i_sect < MAX_SECT - 1)
+                    i_sect++;
+            }
+
+            f_xo = f_xd;
+            f_yo = f_yd;
+        }
+        f_xd = ps_pt[i_pts_nbr - 1].f_x * f_x_ratio + f_x_offset;
+        f_yd = ps_pt[i_pts_nbr - 1].f_y * f_y_ratio + f_y_offset;
+
+// ...fill from this junction to next junction
+        if ( i_y >= 0 )
+        {
+            // last diagonal intersection
+            pi_sects[i_sect] = diagonal_limit( p_filter, i_y, false,
i_plane );
+            if (i_sect < MAX_SECT - 1)
+                i_sect++;
+        }
+
+// ...reorder the list
+        int32_t i_s = 0;
+
+        while (i_s < (i_sect - 1))
+        {
+            if (pi_sects[i_s] > pi_sects[i_s+1])
+            {
+                uint32_t i_temp = pi_sects[i_s];
+                pi_sects[i_s] = pi_sects[i_s+1];
+                pi_sects[i_s+1] = i_temp;
+                i_s = 0;
+            }
+            else
+            {
+                i_s++;
+            }
+        }
+
+// ...we have to convert absolute values to offsets and take into account
min_curve_x
+        i_s = 0;
+        int32_t i_last_x;
+        if ( i_y < 0 )
+            i_last_x = 0;
+        else
+            i_last_x = diagonal_limit( p_filter, i_y, true, i_plane );   //
first diagonal intersection
+
+        for (i_s = 0; i_s<i_sect; i_s++)
+        {
+            int32_t i_current_x = pi_sects[i_s];
+            int32_t i_delta = i_current_x - i_last_x;
+            pi_sects[i_s] = i_delta;
+
+            i_last_x = i_current_x;
+        }
+
+// ...allocate memory and copy final values
+        // note for y > 0 we have to ignore the first offset as it is
included in "Left" piece shape
+        if ( i_y >= 0 )
+        {
+            ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr =
i_sect;
+            ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section =
malloc (  sizeof(row_section_t) * i_sect);
+            for (uint8_t i=0; i < i_sect; i++)
+            {
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = i % 2;
// 0 = fill ; 1 = offset
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+            }
+        }
+        else
+        {
+            ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr =
i_sect;
+            ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section =
malloc (  sizeof(row_section_t) * i_sect);
+            for (uint8_t i=0; i < i_sect; i++)
+            {
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = (i + 1)
% 2; // 0 = fill ; 1 = offset
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+            }
+        }
+    }
+}
+
+static void generate_sectLeft( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_pts_nbr, point_t *ps_pt, uint8_t i_plane)
+{
+
+    if (ps_pt == NULL) {
+        generate_sectLeftB( p_filter, ps_piece_shape, i_plane);
+        return;
+    }
+
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    int32_t i_size_x = p_sys->ps_desk_planes[i_plane].i_pieces_max_x;
+    int32_t i_size_y = p_sys->ps_desk_planes[i_plane].i_pieces_max_y;
+
+    int32_t i_size_x_0 = p_sys->ps_desk_planes[0].i_pieces_max_x;
+    int32_t i_size_y_0 = p_sys->ps_desk_planes[0].i_pieces_max_y;
+
+    float f_x_ratio =  ((float) i_size_x) / ((float) i_size_x_0);
+    float f_y_ratio = ((float) i_size_y) / ((float) i_size_y_0);
+    float f_x_offset = 0;
+    float f_y_offset = 0;
+    float f_bez_x, f_bez_y;
+    float f_xo, f_yo, f_xd, f_yd;
+
+// first: get min x:
+    float f_min_curve_x = ps_pt[0].f_x * f_x_ratio + f_x_offset;
+
+    for (float f_t = 0; f_t <= i_pts_nbr - 1; f_t += 0.1 )
+    {
+        int8_t i_main_t = floor(f_t);
+        if ( i_main_t == i_pts_nbr - 1 )
+            i_main_t = i_pts_nbr - 2;
+        float f_sub_t = f_t - i_main_t;
+
+        f_bez_x = ( 1 - f_sub_t ) * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_pt[ 3 * i_main_t ].f_x
+                + 3 * f_sub_t * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) * ps_pt[
3 * i_main_t + 1 ].f_x
+                + 3 * f_sub_t * f_sub_t * ( 1 - f_sub_t ) * ps_pt[ 3 *
i_main_t + 2 ].f_x
+                + f_sub_t * f_sub_t * f_sub_t * ps_pt[ 3 * i_main_t + 3
].f_x;
+
+        f_xd = f_bez_x * f_x_ratio + f_x_offset;
+
+        if (f_xd < f_min_curve_x)
+            f_min_curve_x = f_xd;
+    }
+    f_min_curve_x = floor(f_min_curve_x);
+    if (f_min_curve_x > 0)
+        f_min_curve_x = 0;
+
+// next: process each horizontal pixel lines:
+    int32_t i_min_y = 0;
+    int32_t i_nb_y = i_size_y;
+
+// allocate memory
+    ps_piece_shape->i_row_nbr = i_nb_y;
+    ps_piece_shape->i_first_row_offset = i_min_y;
+    ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t
) * ps_piece_shape->i_row_nbr );
+
+    for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++)
+    {
+        int32_t i_row = i_y - i_min_y;
+
+        uint8_t i_sect = 0;
+        int32_t pi_sects[MAX_SECT];
+
+// ...detect curve
+        int8_t i_main_t = 0;
+        f_xo = ps_pt[0].f_x * f_x_ratio + f_x_offset;
+        f_yo = ps_pt[0].f_y * f_y_ratio + f_y_offset;
+
+        for (float f_t = 0; f_t <= i_pts_nbr - 1; f_t += 0.1 )
+        {
+            i_main_t = floor(f_t);
+            if ( i_main_t == i_pts_nbr - 1 )
+                i_main_t = i_pts_nbr - 2;
+            float f_sub_t = f_t - i_main_t;
+
+            f_bez_x = ( 1 - f_sub_t ) * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_pt[ 3 * i_main_t ].f_x
+                    + 3 * f_sub_t * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_pt[ 3 * i_main_t + 1 ].f_x
+                    + 3 * f_sub_t * f_sub_t * ( 1 - f_sub_t ) * ps_pt[ 3 *
i_main_t + 2 ].f_x
+                    + f_sub_t * f_sub_t * f_sub_t * ps_pt[ 3 * i_main_t + 3
].f_x;
+
+            f_bez_y = ( 1 - f_sub_t ) * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_pt[ 3 * i_main_t ].f_y
+                    + 3 * f_sub_t * ( 1 - f_sub_t ) * ( 1 - f_sub_t ) *
ps_pt[ 3 * i_main_t + 1 ].f_y
+                    + 3 * f_sub_t * f_sub_t * ( 1 - f_sub_t ) * ps_pt[ 3 *
i_main_t + 2 ].f_y
+                    + f_sub_t * f_sub_t * f_sub_t * ps_pt[ 3 * i_main_t + 3
].f_y;
+
+            f_xd = f_bez_x * f_x_ratio + f_x_offset;
+            f_yd = f_bez_y * f_y_ratio + f_y_offset;
+
+            if ((f_yo < (float)i_y+0.5 && f_yd >= (float)i_y+0.5) || (f_yo
> (float)i_y+0.5 && f_yd <= (float)i_y+0.5))
+            {
+                pi_sects[i_sect] = floor(((float)i_y+0.5 - f_yo) * (f_xd -
f_xo) / (f_yd - f_yo) + f_xo);
+                if (i_sect < MAX_SECT - 1)
+                    i_sect++;
+            }
+
+            f_xo = f_xd;
+            f_yo = f_yd;
+        }
+        f_xd = ps_pt[i_pts_nbr - 1].f_x * f_x_ratio + f_x_offset;
+        f_yd = ps_pt[i_pts_nbr - 1].f_y * f_y_ratio + f_y_offset;
+
+
+// ...fill from this junction to next junction
+        if ( i_y >= 0 )
+        {
+            // last diagonal intersection
+            pi_sects[i_sect] = diagonal_limit( p_filter, i_y, true, i_plane
);
+            if (i_sect < MAX_SECT - 1)
+                i_sect++;
+        }
+
+// ...reorder the list
+        int32_t i_s = 0;
+
+        while (i_s < (i_sect - 1))
+        {
+            if (pi_sects[i_s] > pi_sects[i_s+1])
+            {
+                uint32_t i_temp = pi_sects[i_s];
+                pi_sects[i_s] = pi_sects[i_s+1];
+                pi_sects[i_s+1] = i_temp;
+                i_s = 0;
+            }
+            else
+            {
+                i_s++;
+            }
+        }
+
+// ...we have to convert absolute values to offsets and take into account
min_curve_x
+        i_s = 0;
+        int32_t i_last_x;
+        i_last_x = 0;
+
+        for (i_s = 0; i_s<i_sect; i_s++)
+        {
+            int32_t i_current_x = pi_sects[i_s];
+            int32_t i_delta = i_current_x - i_last_x;
+            pi_sects[i_s] = i_delta;
+
+            i_last_x = i_current_x;
+        }
+
+// ...allocate memory and copy final values
+        // note for y > 0 we have to ignore the first offset as it is
included in "Left" piece shape
+        ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
+        ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_sect);
+        for (uint8_t i=0; i < i_sect; i++)
+        {
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = (i+1) %
2; // 0 = fill ; 1 = offset
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+        }
+    }
+}
+
+//generate Right from Left:
+static void generate_sectLeft2Right( filter_t *p_filter, piece_shape_t
*ps_piece_shape, piece_shape_t *ps_left_piece_shape, uint8_t i_plane)
+{
+    if (ps_left_piece_shape == NULL) {
+        generate_sectRightB( p_filter, ps_piece_shape, i_plane);
+        return;
+    }
+
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    int32_t i_min_y = ps_left_piece_shape->i_first_row_offset;
+    int32_t i_nb_y = ps_left_piece_shape->i_row_nbr;
+
+// allocate memory
+    ps_piece_shape->i_row_nbr = i_nb_y;
+    ps_piece_shape->i_first_row_offset = i_min_y;
+    ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t
) * i_nb_y );
+
+    for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++)
+    {
+        int32_t i_row = i_y - i_min_y;
+
+        int32_t i_size_x = p_sys->ps_desk_planes[i_plane].i_pieces_max_x;
+        int32_t i_left_width = diagonal_limit( p_filter, i_y, true, i_plane
);
+        int32_t i_right_width = i_size_x - diagonal_limit( p_filter, i_y,
false, i_plane );
+        int16_t i_section_nbr =
ps_left_piece_shape->ps_piece_shape_row[i_row].i_section_nbr;
+
+        ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr =
i_section_nbr;
+        ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_section_nbr);
+
+        ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_type
=
+
ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_type;
+        ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_width
=
+
ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_width +
i_right_width - i_left_width;
+
+        for (int8_t i_s=0; i_s<i_section_nbr;i_s++)
+        {
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_type =
+
ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_section_nbr
- 1 - i_s].i_type;
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_width =
+
ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_section_nbr
- 1 - i_s].i_width
+                    + (i_s == 0 ? i_right_width - i_left_width : 0);
+        }
+    }
+}
+
+//generate Btm from Top:
+static void generate_sectTop2Btm( filter_t *p_filter, piece_shape_t
*ps_piece_shape, piece_shape_t *ps_top_piece_shape, uint8_t i_plane)
+{
+    if (ps_top_piece_shape == NULL) {
+        generate_sectBtmB( p_filter, ps_piece_shape, i_plane);
+        return;
+    }
+
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    int32_t i_top_min_y = ps_top_piece_shape->i_first_row_offset;
+    int32_t i_top_nb_y = ps_top_piece_shape->i_row_nbr;
+    int32_t i_size_y = p_sys->ps_desk_planes[i_plane].i_pieces_max_y;
+    int32_t i_max_y = p_sys->ps_desk_planes[i_plane].i_pieces_max_y -
i_top_min_y;
+
+    int32_t i_min_y = i_size_y / 2;
+    int32_t i_nb_y = i_max_y - i_min_y;
+
+// allocate memory
+    ps_piece_shape->i_row_nbr = i_nb_y;
+    ps_piece_shape->i_first_row_offset = i_min_y;
+    ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t
) * i_nb_y );
+
+    for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++)
+    {
+        int32_t i_top_y = 2 * i_min_y - i_y + (i_nb_y - i_top_nb_y);
+        int32_t i_row = i_y - i_min_y;
+        int32_t i_top_row = i_top_y - i_top_min_y;
+
+        if ( i_top_row < 0 || i_top_row >= i_top_nb_y )
+        { // the line does not exist in top
+            ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = 1;
+            ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section =
malloc (  sizeof(row_section_t) * 1);
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_type = 0;
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_width =
+                diagonal_limit( p_filter, i_y, false, i_plane ) - 1 -
(diagonal_limit( p_filter, i_y, true, i_plane ) - 1);
+        }
+        else
+        { // copy the line from TopShape
+            int32_t i_top_width =
+                diagonal_limit( p_filter, i_top_y, false, i_plane ) - 1 -
(diagonal_limit( p_filter, i_top_y, true, i_plane ) - 1);
+            int32_t i_width =
+                diagonal_limit( p_filter, i_y, false, i_plane ) - 1 -
(diagonal_limit( p_filter, i_y, true, i_plane ) - 1);
+            int32_t i_left_adjust = ( i_width - i_top_width ) / 2;
+            int32_t i_right_adjust = ( i_width - i_top_width ) -
i_left_adjust;
+
+            int8_t i_section_nbr =
ps_top_piece_shape->ps_piece_shape_row[i_top_row].i_section_nbr;
+            ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr =
i_section_nbr;
+            ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section =
malloc (  sizeof(row_section_t) * i_section_nbr);
+
+            for (int8_t i_s=0; i_s<i_section_nbr; i_s++)
+            {
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_type =
+
ps_top_piece_shape->ps_piece_shape_row[i_top_row].ps_row_section[i_s].i_type
;
+
ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_width =
+
ps_top_piece_shape->ps_piece_shape_row[i_top_row].ps_row_section[i_s].i_widt
h
+                        + (i_s == 0 ? i_left_adjust : (i_s ==
i_section_nbr-1 ? i_right_adjust : 0));
+            }
+        }
+    }
+}
+
+static void save(filter_t *p_filter)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    FILE *ofp;
+    char sav_filename[] = "pzl_001.sav";
+
+    uint32_t i_orow, i_ocol;
+    int8_t i_angle, i_mirror;
+    float f_pos_x, f_pos_y;
+
+    ofp = fopen(sav_filename, "w");
+
+    if (ofp != NULL) {
+        fprintf(ofp, "%d %d %d\n", p_sys->s_allocated.i_rows,
p_sys->s_allocated.i_cols, p_sys->s_allocated.i_rotate);
+
+        uint32_t i=0;
+        for (uint32_t i_row = 0; i_row < (uint32_t)
p_sys->s_allocated.i_rows; i_row++)
+            for (uint32_t i_col = 0; i_col < (uint32_t)
p_sys->s_allocated.i_cols; i_col++)
+            {
+                int32_t i_border;
+                i_border = p_sys->ps_desk_planes[0].i_visible_pitch *
(p_sys->s_current_param.i_border / 100 / 2);
+                f_pos_x = (
p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_x - i_border ) /
((float)p_sys->ps_desk_planes[0].i_visible_pitch - 2*i_border);
+                i_border = p_sys->ps_desk_planes[0].i_visible_lines *
(p_sys->s_current_param.i_border / 100 / 2);
+                f_pos_y = (
p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_y - i_border ) /
((float)p_sys->ps_desk_planes[0].i_visible_lines - 2*i_border);
+                i_orow = p_sys->ps_pieces[i].i_original_row;
+                i_ocol = p_sys->ps_pieces[i].i_original_col;
+                i_angle = p_sys->ps_pieces[i].i_actual_angle;
+                i_mirror = p_sys->ps_pieces[i].i_actual_mirror;
+
+                fprintf(ofp, "%d %d %f %f %d %d\n", i_orow, i_ocol,
f_pos_x, f_pos_y, i_angle, i_mirror);
+                fprintf(ofp, "%d %d %d %d\n",
p_sys->ps_pieces[i].i_top_shape, p_sys->ps_pieces[i].i_btm_shape,
p_sys->ps_pieces[i].i_right_shape, p_sys->ps_pieces[i].i_left_shape);
+
+                i++;
+            }
+
+        fclose(ofp);
+    }
+}
+
+static void load( filter_t *p_filter)
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    FILE *ifp;
+    char sav_filename[] = "pzl_001.sav";
+
+    ifp = fopen(sav_filename, "r");
+
+    if (ifp != NULL) {
+
+        if (feof(ifp))
+            return;
+
+        int i_rows, i_cols;
+        int i_rotate;
+
+        if (feof(ifp) || (fscanf(ifp, "%d %d %d", &i_rows, &i_cols,
&i_rotate) != 3))
+            return;
+
+        if (p_sys->s_current_param.i_cols != i_cols ||
p_sys->s_allocated.i_rows != i_rows || p_sys->s_allocated.i_rotate !=
i_rotate)
+            return;
+
+        int i_orow, i_ocol;
+        int i_angle, i_mirror;
+        float f_pos_x, f_pos_y;
+        int i_top_shape, i_btm_shape, i_right_shape, i_left_shape;
+
+        for (uint32_t i_sav_pce=0; i_sav_pce <
p_sys->s_allocated.i_pieces_nbr; i_sav_pce++) {
+            if (feof(ifp) || (fscanf(ifp, "%d %d %f %f %d %d", &i_orow,
&i_ocol, &f_pos_x, &f_pos_y, &i_angle, &i_mirror) != 6))
+                return;
+            if (feof(ifp) || (fscanf(ifp, "%d %d %d %d", &i_top_shape,
&i_btm_shape, &i_right_shape, &i_left_shape) != 4))
+                return;
+
+            for (uint32_t i=0; i < p_sys->s_allocated.i_pieces_nbr; i++)
+                if (p_sys->ps_pieces[i].i_original_row == i_orow &&
p_sys->ps_pieces[i].i_original_col == i_ocol) {
+
+                    int32_t i_border;
+                    i_border = p_sys->ps_desk_planes[0].i_visible_pitch *
(p_sys->s_current_param.i_border / 100 / 2);
+                    p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_x =
+                            i_border +
((float)p_sys->ps_desk_planes[0].i_visible_pitch - 2*i_border) * f_pos_x;
+                    i_border = p_sys->ps_desk_planes[0].i_visible_lines *
(p_sys->s_current_param.i_border / 100 / 2);
+                    p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_y =
+                            i_border +
((float)p_sys->ps_desk_planes[0].i_visible_lines - 2*i_border) * f_pos_y;
+
+                    p_sys->ps_pieces[i].i_top_shape = i_top_shape;
+                    p_sys->ps_pieces[i].i_btm_shape = i_btm_shape;
+                    p_sys->ps_pieces[i].i_right_shape = i_right_shape;
+                    p_sys->ps_pieces[i].i_left_shape = i_left_shape;
+                    p_sys->ps_pieces[i].i_actual_angle = i_angle;
+                    p_sys->ps_pieces[i].i_actual_mirror = i_mirror;
+                    p_sys->ps_pieces[i].i_group_ID = i_sav_pce;
+                    p_sys->ps_pieces[i].b_finished = false;
+
+                    calculate_corners( p_filter, i );
+
+                    break;
+                }
+        }
+
+        fclose(ifp);
+    }
 }
-- 
1.7.9.5








More information about the vlc-devel mailing list