]> git.sesse.net Git - vlc/blobdiff - modules/video_filter/puzzle.c
s/vout_Destroy/vlc_object_release/ - A cat is a cat
[vlc] / modules / video_filter / puzzle.c
index 77baa157a868e295e6346e0ef621f12fa29e5f96..c2bcfd76ea46a712a34f45731e0885659c490c28 100644 (file)
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
-#include <stdlib.h>                                      /* malloc(), free() */
-#include <string.h>
 
-#include <vlc/vlc.h>
-#include <vlc/vout.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_vout.h>
 
 #include <math.h>
 
@@ -52,6 +55,9 @@ static int  SendEvents   ( vlc_object_t *, char const *,
 static int  MouseEvent   ( vlc_object_t *, char const *,
                            vlc_value_t, vlc_value_t, void * );
 
+static int PuzzleCallback( vlc_object_t *, char const *,
+                           vlc_value_t, vlc_value_t, void * );
+
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
@@ -60,22 +66,32 @@ static int  MouseEvent   ( vlc_object_t *, char const *,
 #define ROWS_LONGTEXT N_("Number of puzzle rows")
 #define COLS_TEXT N_("Number of puzzle columns")
 #define COLS_LONGTEXT N_("Number of puzzle columns")
+#define BLACKSLOT_TEXT N_("Make one tile a black slot")
+#define BLACKSLOT_LONGTEXT N_("Make one slot black. Other tiles can only be swapped with the black slot.")
+
+#define CFG_PREFIX "puzzle-"
 
 vlc_module_begin();
-    set_description( _("Puzzle interactive game video filter") );
-    set_shortname( _( "Puzzle" ));
+    set_description( N_("Puzzle interactive game video filter") );
+    set_shortname( N_( "Puzzle" ));
     set_capability( "video filter", 0 );
     set_category( CAT_VIDEO );
     set_subcategory( SUBCAT_VIDEO_VFILTER );
 
-    add_integer_with_range( "puzzle-rows", 4, 1, 128, NULL,
-                            ROWS_TEXT, ROWS_LONGTEXT, VLC_FALSE );
-    add_integer_with_range( "puzzle-cols", 4, 1, 128, NULL,
-                            COLS_TEXT, COLS_LONGTEXT, VLC_FALSE );
+    add_integer_with_range( CFG_PREFIX "rows", 4, 1, 128, NULL,
+                            ROWS_TEXT, ROWS_LONGTEXT, false );
+    add_integer_with_range( CFG_PREFIX "cols", 4, 1, 128, NULL,
+                            COLS_TEXT, COLS_LONGTEXT, false );
+    add_bool( CFG_PREFIX "black-slot", 0, NULL,
+              BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, false );
 
     set_callbacks( Create, Destroy );
 vlc_module_end();
 
+static const char *const ppsz_filter_options[] = {
+    "rows", "cols", "black-slot", NULL
+};
+
 /*****************************************************************************
  * vout_sys_t: Magnify video output method descriptor
  *****************************************************************************/
@@ -89,7 +105,9 @@ struct vout_sys_t
     int i_rows;
     int *pi_order;
     int i_selected;
-    vlc_bool_t b_finished;
+    bool b_finished;
+
+    bool b_blackslot;
 };
 
 /*****************************************************************************
@@ -103,14 +121,35 @@ static int Control( vout_thread_t *p_vout, int i_query, va_list args )
 /*****************************************************************************
  * Misc stuff...
  *****************************************************************************/
-static vlc_bool_t finished( vout_sys_t *p_sys )
+static bool finished( vout_sys_t *p_sys )
 {
     int i;
     for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
     {
-        if( i != p_sys->pi_order[i] ) return VLC_FALSE;
+        if( i != p_sys->pi_order[i] ) return false;
+    }
+    return true;
+}
+static bool is_valid( vout_sys_t *p_sys )
+{
+    int i, j, d=0;
+    if( p_sys->b_blackslot == false ) return true;
+    for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
+    {
+        if( p_sys->pi_order[i] == p_sys->i_cols * p_sys->i_rows - 1 )
+        {
+            d += i / p_sys->i_cols + 1;
+            continue;
+        }
+        for( j = i+1; j < p_sys->i_cols * p_sys->i_rows; j++ )
+        {
+            if( p_sys->pi_order[j] == p_sys->i_cols * p_sys->i_rows - 1 )
+                continue;
+            if( p_sys->pi_order[i] > p_sys->pi_order[j] ) d++;
+        }
     }
-    return VLC_TRUE;
+    if( d%2!=0 ) return false;
+    else return true;
 }
 static void shuffle( vout_sys_t *p_sys )
 {
@@ -134,7 +173,25 @@ static void shuffle( vout_sys_t *p_sys )
             }
         }
         p_sys->b_finished = finished( p_sys );
-    } while( p_sys->b_finished == VLC_TRUE );
+    } while(    p_sys->b_finished == true
+             || is_valid( p_sys ) == false );
+
+    if( p_sys->b_blackslot == true )
+    {
+        for( i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
+        {
+            if( p_sys->pi_order[i] ==
+                p_sys->i_cols * p_sys->i_rows - 1 )
+            {
+                p_sys->i_selected = i;
+                break;
+            }
+        }
+    }
+    else
+    {
+        p_sys->i_selected = -1;
+    }
 }
 
 /*****************************************************************************
@@ -154,9 +211,21 @@ static int Create( vlc_object_t *p_this )
 
     p_vout->p_sys->p_image = image_HandlerCreate( p_vout );
 
-    p_vout->p_sys->i_rows = config_GetInt( p_vout, "puzzle-rows" );
-    p_vout->p_sys->i_cols = config_GetInt( p_vout, "puzzle-cols" );
-    p_vout->p_sys->i_selected = -1;
+    config_ChainParse( p_vout, CFG_PREFIX, ppsz_filter_options,
+                       p_vout->p_cfg );
+
+    p_vout->p_sys->i_rows =
+        var_CreateGetIntegerCommand( p_vout, CFG_PREFIX "rows" );
+    p_vout->p_sys->i_cols =
+        var_CreateGetIntegerCommand( p_vout, CFG_PREFIX "cols" );
+    p_vout->p_sys->b_blackslot =
+        var_CreateGetBoolCommand( p_vout, CFG_PREFIX "black-slot" );
+    var_AddCallback( p_vout, CFG_PREFIX "rows",
+                     PuzzleCallback, p_vout->p_sys );
+    var_AddCallback( p_vout, CFG_PREFIX "cols",
+                     PuzzleCallback, p_vout->p_sys );
+    var_AddCallback( p_vout, CFG_PREFIX "black-slot",
+                     PuzzleCallback, p_vout->p_sys );
 
     p_vout->p_sys->pi_order = NULL;
     shuffle( p_vout->p_sys );
@@ -178,7 +247,8 @@ static int Init( vout_thread_t *p_vout )
 {
     int i_index;
     picture_t *p_pic;
-    video_format_t fmt = {0};
+    video_format_t fmt;
+    memset( &fmt, 0, sizeof( video_format_t ) );
 
     I_OUTPUTPICTURES = 0;
 
@@ -234,6 +304,25 @@ static void End( vout_thread_t *p_vout )
     var_DelCallback( p_vout->p_sys->p_vout, "mouse-clicked", MouseEvent, p_vout);
 }
 
+#define SHUFFLE_WIDTH 81
+#define SHUFFLE_HEIGHT 13
+static const char *shuffle_button[] =
+{
+".................................................................................",
+"..............  ............................   ........   ......  ...............",
+"..............  ...........................  .........  ........  ...............",
+"..............  ...........................  .........  ........  ...............",
+"..     .......  .    .......  ....  ......     ......     ......  ........    ...",
+".  .... ......   ...  ......  ....  .......  .........  ........  .......  ..  ..",
+".  ...........  ....  ......  ....  .......  .........  ........  ......  ....  .",
+".      .......  ....  ......  ....  .......  .........  ........  ......        .",
+"..      ......  ....  ......  ....  .......  .........  ........  ......  .......",
+"......  ......  ....  ......  ....  .......  .........  ........  ......  .......",
+". ....  ......  ....  ......  ...   .......  .........  ........  .......  .... .",
+"..     .......  ....  .......    .  .......  .........  ........  ........     ..",
+"................................................................................."};
+
+
 /*****************************************************************************
  * Destroy: destroy Magnify video thread output method
  *****************************************************************************/
@@ -245,7 +334,7 @@ static void Destroy( vlc_object_t *p_this )
     {
         DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
         vlc_object_detach( p_vout->p_sys->p_vout );
-        vout_Destroy( p_vout->p_sys->p_vout );
+        vlc_object_release( p_vout->p_sys->p_vout );
     }
 
     image_HandlerDelete( p_vout->p_sys->p_image );
@@ -263,7 +352,8 @@ static void Render( vout_thread_t *p_vout, picture_t *p_pic )
 {
     picture_t *p_outpic;
 
-    //video_format_t fmt_out = {0};
+    //video_format_t fmt_out;
+    // memset( &fmt_out, 0, sizeof(video_format_t) );
     //picture_t *p_converted;
 
     int i_plane;
@@ -302,18 +392,34 @@ static void Render( vout_thread_t *p_vout, picture_t *p_pic )
             i_row *= p_in->i_lines / i_rows;
             i_last_row *= p_in->i_lines / i_rows;
 
-            for( ; i_row < i_last_row; i_row++, i_orow++ )
+            if( p_vout->p_sys->b_blackslot == true
+                && p_vout->p_sys->b_finished == false
+                && i == p_vout->p_sys->i_selected )
             {
-                memcpy( p_out->p_pixels + i_row * i_pitch
-                                        + i_col * i_pitch / i_cols,
-                        p_in->p_pixels + i_orow * i_pitch
-                                       + i_ocol * i_pitch / i_cols,
-                        i_pitch / i_cols );
+                uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
+                for( ; i_row < i_last_row; i_row++, i_orow++ )
+                {
+                    vlc_memset( p_out->p_pixels + i_row * i_pitch
+                                               + i_col * i_pitch / i_cols,
+                               color, i_pitch / i_cols );
+                }
+            }
+            else
+            {
+                for( ; i_row < i_last_row; i_row++, i_orow++ )
+                {
+                    vlc_memcpy( p_out->p_pixels + i_row * i_pitch
+                                               + i_col * i_pitch / i_cols,
+                               p_in->p_pixels + i_orow * i_pitch
+                                              + i_ocol * i_pitch / i_cols,
+                               i_pitch / i_cols );
+                }
             }
         }
     }
 
-    if( p_vout->p_sys->i_selected != -1 )
+    if(    p_vout->p_sys->i_selected != -1
+        && p_vout->p_sys->b_blackslot == false )
     {
         plane_t *p_in = p_pic->p+Y_PLANE;
         plane_t *p_out = p_outpic->p+Y_PLANE;
@@ -323,9 +429,9 @@ static void Render( vout_thread_t *p_vout, picture_t *p_pic )
         int i_last_row = i_row + 1;
         i_row *= p_in->i_lines / i_rows;
         i_last_row *= p_in->i_lines / i_rows;
-        memset( p_out->p_pixels + i_row * i_pitch
-                                + i_col * i_pitch / i_cols,
-                0xff, i_pitch / i_cols );
+        vlc_memset( p_out->p_pixels + i_row * i_pitch
+                                   + i_col * i_pitch / i_cols,
+                   0xff, i_pitch / i_cols );
         for( ; i_row < i_last_row; i_row++ )
         {
             p_out->p_pixels[   i_row * i_pitch
@@ -334,9 +440,24 @@ static void Render( vout_thread_t *p_vout, picture_t *p_pic )
                              + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff;
         }
         i_row--;
-        memset( p_out->p_pixels + i_row * i_pitch
-                                + i_col * i_pitch / i_cols,
-                0xff, i_pitch / i_cols );
+        vlc_memset( p_out->p_pixels + i_row * i_pitch
+                                   + i_col * i_pitch / i_cols,
+                   0xff, i_pitch / i_cols );
+    }
+
+    if( p_vout->p_sys->b_finished == true )
+    {
+        int i, j;
+        plane_t *p_out = p_outpic->p+Y_PLANE;
+        int i_pitch = p_out->i_pitch;
+        for( i = 0; i < SHUFFLE_HEIGHT; i++ )
+        {
+            for( j = 0; j < SHUFFLE_WIDTH; j++ )
+            {
+                if( shuffle_button[i][j] == '.' )
+                   p_out->p_pixels[ i * i_pitch + j ] = 0xff;
+            }
+        }
     }
 
     vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
@@ -348,6 +469,8 @@ static void Render( vout_thread_t *p_vout, picture_t *p_pic )
 static int SendEvents( vlc_object_t *p_this, char const *psz_var,
                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
+    VLC_UNUSED(p_this); VLC_UNUSED(oldval);
+
     var_Set( (vlc_object_t *)p_data, psz_var, newval );
 
     return VLC_SUCCESS;
@@ -359,6 +482,7 @@ static int SendEvents( vlc_object_t *p_this, char const *psz_var,
 static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
+    VLC_UNUSED(p_data); VLC_UNUSED(oldval);
     vout_thread_t *p_vout = (vout_thread_t *)p_this;
     var_Set( p_vout->p_sys->p_vout, psz_var, newval );
     return VLC_SUCCESS;
@@ -370,6 +494,7 @@ static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
 static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
+    VLC_UNUSED(p_this); VLC_UNUSED(oldval); VLC_UNUSED(newval);
     vout_thread_t *p_vout = (vout_thread_t*)p_data;
     int i_x, i_y;
     int i_v;
@@ -394,10 +519,14 @@ static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
     i_y = var_GetInteger( p_vout->p_sys->p_vout, "mouse-y" );
     i_x = var_GetInteger( p_vout->p_sys->p_vout, "mouse-x" );
 
+    if( i_y < 0 || i_x < 0 || i_y >= v_h || i_x >= v_w )
+        return VLC_SUCCESS;
+
     if( mouse & MOUSE_CLICKED )
     {
         i_pos = p_vout->p_sys->i_cols * ( ( p_vout->p_sys->i_rows * i_y ) / v_h ) + (p_vout->p_sys->i_cols * i_x ) / v_w;
-        if( p_vout->p_sys->b_finished == VLC_TRUE )
+        if( p_vout->p_sys->b_finished == true
+            && i_x < SHUFFLE_WIDTH && i_y < SHUFFLE_HEIGHT )
         {
             shuffle( p_vout->p_sys );
         }
@@ -405,12 +534,15 @@ static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
         {
             p_vout->p_sys->i_selected = i_pos;
         }
-        else if( p_vout->p_sys->i_selected == i_pos )
+        else if( p_vout->p_sys->i_selected == i_pos
+                 && p_vout->p_sys->b_blackslot == false )
         {
             p_vout->p_sys->i_selected = -1;
         }
-        else if(    p_vout->p_sys->i_selected == i_pos + 1
-                 || p_vout->p_sys->i_selected == i_pos - 1
+        else if(    ( p_vout->p_sys->i_selected == i_pos + 1
+                      && p_vout->p_sys->i_selected%p_vout->p_sys->i_cols != 0 )
+                 || ( p_vout->p_sys->i_selected == i_pos - 1
+                      && i_pos % p_vout->p_sys->i_cols != 0 )
                  || p_vout->p_sys->i_selected == i_pos + p_vout->p_sys->i_cols
                  || p_vout->p_sys->i_selected == i_pos - p_vout->p_sys->i_cols )
         {
@@ -418,10 +550,35 @@ static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
             p_vout->p_sys->pi_order[ p_vout->p_sys->i_selected ] =
                 p_vout->p_sys->pi_order[ i_pos ];
             p_vout->p_sys->pi_order[ i_pos ] = a;
-            p_vout->p_sys->i_selected = -1;
+            if( p_vout->p_sys->b_blackslot == true )
+                p_vout->p_sys->i_selected = i_pos;
+            else
+                p_vout->p_sys->i_selected = -1;
 
             p_vout->p_sys->b_finished = finished( p_vout->p_sys );
         }
     }
     return VLC_SUCCESS;
 }
+
+static int PuzzleCallback( vlc_object_t *p_this, char const *psz_var,
+                           vlc_value_t oldval, vlc_value_t newval,
+                           void *p_data )
+{
+    VLC_UNUSED(p_this); VLC_UNUSED(oldval);
+    vout_sys_t *p_sys = (vout_sys_t *)p_data;
+    if( !strcmp( psz_var, CFG_PREFIX "rows" ) )
+    {
+        p_sys->i_rows = __MAX( 1, newval.i_int );
+    }
+    else if( !strcmp( psz_var, CFG_PREFIX "cols" ) )
+    {
+        p_sys->i_cols = __MAX( 1, newval.i_int );
+    }
+    else if( !strcmp( psz_var, CFG_PREFIX "black-slot" ) )
+    {
+        p_sys->b_blackslot = newval.b_bool;
+    }
+    shuffle( p_sys );
+    return VLC_SUCCESS;
+}