Clarify live555 version error
[vlc/asuraparaju-public.git] / modules / video_filter / puzzle.c
blobb50fd49d195b8ed3b0f5b64ef7f152f342793a18
1 /*****************************************************************************
2 * puzzle.c : Puzzle game
3 *****************************************************************************
4 * Copyright (C) 2005-2009 the VideoLAN team
5 * $Id$
7 * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #include <math.h>
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
36 #include <vlc_rand.h>
38 #include "filter_picture.h"
40 /*****************************************************************************
41 * Module descriptor
42 *****************************************************************************/
43 #define ROWS_TEXT N_("Number of puzzle rows")
44 #define ROWS_LONGTEXT N_("Number of puzzle rows")
45 #define COLS_TEXT N_("Number of puzzle columns")
46 #define COLS_LONGTEXT N_("Number of puzzle columns")
47 #define BLACKSLOT_TEXT N_("Make one tile a black slot")
48 #define BLACKSLOT_LONGTEXT N_("Make one slot black. Other tiles can only be swapped with the black slot.")
50 #define CFG_PREFIX "puzzle-"
52 static int Open ( vlc_object_t * );
53 static void Close( vlc_object_t * );
55 vlc_module_begin()
56 set_description( N_("Puzzle interactive game video filter") )
57 set_shortname( N_( "Puzzle" ))
58 set_capability( "video filter2", 0 )
59 set_category( CAT_VIDEO )
60 set_subcategory( SUBCAT_VIDEO_VFILTER )
62 add_integer_with_range( CFG_PREFIX "rows", 4, 2, 16, NULL,
63 ROWS_TEXT, ROWS_LONGTEXT, false )
64 add_integer_with_range( CFG_PREFIX "cols", 4, 2, 16, NULL,
65 COLS_TEXT, COLS_LONGTEXT, false )
66 add_bool( CFG_PREFIX "black-slot", false, NULL,
67 BLACKSLOT_TEXT, BLACKSLOT_LONGTEXT, false )
69 set_callbacks( Open, Close )
70 vlc_module_end()
73 /*****************************************************************************
74 * Local prototypes
75 *****************************************************************************/
76 static const char *const ppsz_filter_options[] = {
77 "rows", "cols", "black-slot", NULL
80 static picture_t *Filter( filter_t *, picture_t * );
81 static int Mouse( filter_t *, vlc_mouse_t *, const vlc_mouse_t *, const vlc_mouse_t * );
83 static bool IsFinished( filter_sys_t * );
84 static void Shuffle( filter_sys_t * );
85 static int PuzzleCallback( vlc_object_t *, char const *,
86 vlc_value_t, vlc_value_t, void * );
88 struct filter_sys_t
90 /* */
91 int i_cols;
92 int i_rows;
93 bool b_blackslot;
94 int *pi_order;
95 int i_selected;
96 bool b_finished;
98 /* */
99 vlc_mutex_t lock;
100 bool b_change;
101 struct
103 int i_cols;
104 int i_rows;
105 bool b_blackslot;
106 } change;
109 #define SHUFFLE_WIDTH 81
110 #define SHUFFLE_HEIGHT 13
111 static const char *shuffle_button[] =
113 ".................................................................................",
114 ".............. ............................ ........ ...... ...............",
115 ".............. ........................... ......... ........ ...............",
116 ".............. ........................... ......... ........ ...............",
117 ".. ....... . ....... .... ...... ...... ...... ........ ...",
118 ". .... ...... ... ...... .... ....... ......... ........ ....... .. ..",
119 ". ........... .... ...... .... ....... ......... ........ ...... .... .",
120 ". ....... .... ...... .... ....... ......... ........ ...... .",
121 ".. ...... .... ...... .... ....... ......... ........ ...... .......",
122 "...... ...... .... ...... .... ....... ......... ........ ...... .......",
123 ". .... ...... .... ...... ... ....... ......... ........ ....... .... .",
124 ".. ....... .... ....... . ....... ......... ........ ........ ..",
125 "................................................................................."
130 * Open the filter
132 static int Open( vlc_object_t *p_this )
134 filter_t *p_filter = (filter_t *)p_this;
135 filter_sys_t *p_sys;
137 /* */
138 if( !es_format_IsSimilar( &p_filter->fmt_in, &p_filter->fmt_out ) )
140 msg_Err( p_filter, "Input and output format does not match" );
141 return VLC_EGENERIC;
144 /* Allocate structure */
145 p_filter->p_sys = p_sys = malloc( sizeof( *p_sys ) );
146 if( !p_sys )
147 return VLC_ENOMEM;
149 config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options,
150 p_filter->p_cfg );
152 p_sys->pi_order = NULL;
154 vlc_mutex_init( &p_sys->lock );
155 p_sys->change.i_rows =
156 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "rows" );
157 p_sys->change.i_cols =
158 var_CreateGetIntegerCommand( p_filter, CFG_PREFIX "cols" );
159 p_sys->change.b_blackslot =
160 var_CreateGetBoolCommand( p_filter, CFG_PREFIX "black-slot" );
161 p_sys->b_change = true;
163 var_AddCallback( p_filter, CFG_PREFIX "rows", PuzzleCallback, p_sys );
164 var_AddCallback( p_filter, CFG_PREFIX "cols", PuzzleCallback, p_sys );
165 var_AddCallback( p_filter, CFG_PREFIX "black-slot", PuzzleCallback, p_sys );
167 p_filter->pf_video_filter = Filter;
168 p_filter->pf_video_mouse = Mouse;
170 return VLC_SUCCESS;
174 * Close the filter
176 static void Close( vlc_object_t *p_this )
178 filter_t *p_filter = (filter_t *)p_this;
179 filter_sys_t *p_sys = p_filter->p_sys;
181 var_DelCallback( p_filter, CFG_PREFIX "rows", PuzzleCallback, p_sys );
182 var_DelCallback( p_filter, CFG_PREFIX "cols", PuzzleCallback, p_sys );
183 var_DelCallback( p_filter, CFG_PREFIX "black-slot", PuzzleCallback, p_sys );
185 vlc_mutex_destroy( &p_sys->lock );
186 free( p_sys->pi_order );
188 free( p_sys );
192 * Filter a picture
194 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
196 filter_sys_t *p_sys = p_filter->p_sys;
198 picture_t *p_outpic = filter_NewPicture( p_filter );
199 if( !p_outpic )
201 picture_Release( p_pic );
202 return NULL;
205 /* */
206 vlc_mutex_lock( &p_sys->lock );
207 if( p_sys->b_change )
209 p_sys->i_rows = p_sys->change.i_rows;
210 p_sys->i_cols = p_sys->change.i_cols;
211 p_sys->b_blackslot = p_sys->change.b_blackslot;
212 p_sys->b_change = false;
214 Shuffle( p_sys );
216 vlc_mutex_unlock( &p_sys->lock );
218 /* */
219 const int i_rows = p_sys->i_rows;
220 const int i_cols = p_sys->i_cols;
222 /* Draw each piece of the puzzle at the right place */
223 for( int i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ )
225 const plane_t *p_in = &p_pic->p[i_plane];
226 plane_t *p_out = &p_outpic->p[i_plane];
228 for( int i = 0; i < i_cols * i_rows; i++ )
230 int i_piece_height = p_out->i_visible_lines / i_rows;
231 int i_piece_width = p_out->i_visible_pitch / i_cols;
233 int i_col = (i % i_cols) * i_piece_width;
234 int i_row = (i / i_cols) * i_piece_height;
235 int i_last_row = i_row + i_piece_height;
237 int i_ocol = (p_sys->pi_order[i] % i_cols) * i_piece_width;
238 int i_orow = (p_sys->pi_order[i] / i_cols) * i_piece_height;
240 if( p_sys->b_blackslot && !p_sys->b_finished && i == p_sys->i_selected )
242 uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 );
243 for( int r = i_row; r < i_last_row; r++ )
245 memset( p_out->p_pixels + r * p_out->i_pitch + i_col,
246 color, i_piece_width );
249 else
251 for( int r = i_row, or = i_orow; r < i_last_row; r++, or++ )
253 memcpy( p_out->p_pixels + r * p_out->i_pitch + i_col,
254 p_in->p_pixels + or * p_in->i_pitch + i_ocol,
255 i_piece_width );
259 /* Draw the borders of the selected slot */
260 if( i_plane == 0 && !p_sys->b_blackslot && p_sys->i_selected == i )
262 memset( p_out->p_pixels + i_row * p_out->i_pitch + i_col,
263 0xff, i_piece_width );
264 for( int r = i_row; r < i_last_row; r++ )
266 p_out->p_pixels[r * p_out->i_pitch + i_col + 0 + 0 ] = 0xff;
267 p_out->p_pixels[r * p_out->i_pitch + i_col + i_piece_width - 1 ] = 0xff;
269 memset( p_out->p_pixels + (i_last_row - 1) * p_out->i_pitch + i_col,
270 0xff, i_piece_width );
275 /* Draw the 'Shuffle' button if the puzzle is finished */
276 if( p_sys->b_finished )
278 plane_t *p_out = &p_outpic->p[Y_PLANE];
279 for( int i = 0; i < SHUFFLE_HEIGHT; i++ )
281 for( int j = 0; j < SHUFFLE_WIDTH; j++ )
283 if( shuffle_button[i][j] == '.' )
284 p_out->p_pixels[ i * p_out->i_pitch + j ] = 0xff;
289 return CopyInfoAndRelease( p_outpic, p_pic );
292 static int Mouse( filter_t *p_filter, vlc_mouse_t *p_mouse,
293 const vlc_mouse_t *p_old, const vlc_mouse_t *p_new )
295 filter_sys_t *p_sys = p_filter->p_sys;
296 const video_format_t *p_fmt = &p_filter->fmt_in.video;
298 /* Only take events inside the puzzle erea */
299 if( p_new->i_x < 0 || p_new->i_x >= (int)p_fmt->i_width ||
300 p_new->i_y < 0 || p_new->i_y >= (int)p_fmt->i_height )
301 return VLC_EGENERIC;
303 /* */
304 const bool b_clicked = vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT );
306 /* If the puzzle is finished, shuffle it if needed */
307 if( p_sys->b_finished )
309 if( b_clicked &&
310 p_new->i_x < SHUFFLE_WIDTH && p_new->i_y < SHUFFLE_HEIGHT )
312 p_sys->b_change = true;
313 return VLC_EGENERIC;
315 else
317 /* This is the only case where we can forward the mouse */
318 *p_mouse = *p_new;
319 return VLC_SUCCESS;
322 if( !b_clicked )
323 return VLC_EGENERIC;
325 /* */
326 const int i_pos_x = p_new->i_x * p_sys->i_cols / p_fmt->i_width;
327 const int i_pos_y = p_new->i_y * p_sys->i_rows / p_fmt->i_height;
328 const int i_pos = i_pos_y * p_sys->i_cols + i_pos_x;
330 if( p_sys->i_selected == -1 )
332 p_sys->i_selected = i_pos;
334 else if( p_sys->i_selected == i_pos && !p_sys->b_blackslot )
336 p_sys->i_selected = -1;
338 else if( ( p_sys->i_selected == i_pos + 1 && p_sys->i_selected%p_sys->i_cols != 0 )
339 || ( p_sys->i_selected == i_pos - 1 && i_pos % p_sys->i_cols != 0 )
340 || p_sys->i_selected == i_pos + p_sys->i_cols
341 || p_sys->i_selected == i_pos - p_sys->i_cols )
343 /* Swap two pieces */
344 int a = p_sys->pi_order[ p_sys->i_selected ];
345 p_sys->pi_order[ p_sys->i_selected ] = p_sys->pi_order[ i_pos ];
346 p_sys->pi_order[ i_pos ] = a;
348 p_sys->i_selected = p_sys->b_blackslot ? i_pos : -1;
349 p_sys->b_finished = IsFinished( p_sys );
351 return VLC_EGENERIC;
354 /*****************************************************************************
355 * Misc stuff...
356 *****************************************************************************/
357 static int PuzzleCallback( vlc_object_t *p_this, char const *psz_var,
358 vlc_value_t oldval, vlc_value_t newval,
359 void *p_data )
361 VLC_UNUSED(p_this); VLC_UNUSED(oldval);
362 filter_sys_t *p_sys = (filter_sys_t *)p_data;
364 vlc_mutex_lock( &p_sys->lock );
365 if( !strcmp( psz_var, CFG_PREFIX "rows" ) )
367 p_sys->change.i_rows = __MAX( 1, newval.i_int );
369 else if( !strcmp( psz_var, CFG_PREFIX "cols" ) )
371 p_sys->change.i_cols = __MAX( 1, newval.i_int );
373 else if( !strcmp( psz_var, CFG_PREFIX "black-slot" ) )
375 p_sys->change.b_blackslot = newval.b_bool;
377 p_sys->b_change = true;
378 vlc_mutex_unlock( &p_sys->lock );
380 return VLC_SUCCESS;
383 static bool IsFinished( filter_sys_t *p_sys )
385 for( int i = 0; i < p_sys->i_cols * p_sys->i_rows; i++ )
387 if( i != p_sys->pi_order[i] )
388 return false;
390 return true;
393 static bool IsValid( filter_sys_t *p_sys )
395 const int i_count = p_sys->i_cols * p_sys->i_rows;
397 if( !p_sys->b_blackslot )
398 return true;
400 int d = 0;
401 for( int i = 0; i < i_count; i++ )
403 if( p_sys->pi_order[i] == i_count - 1 )
405 d += i / p_sys->i_cols + 1;
406 continue;
408 for( int j = i+1; j < i_count; j++ )
410 if( p_sys->pi_order[j] == i_count - 1 )
411 continue;
412 if( p_sys->pi_order[i] > p_sys->pi_order[j] )
413 d++;
416 return (d%2) == 0;
419 static void Shuffle( filter_sys_t *p_sys )
421 const unsigned i_count = p_sys->i_cols * p_sys->i_rows;
423 free( p_sys->pi_order );
425 p_sys->pi_order = calloc( i_count, sizeof(*p_sys->pi_order) );
428 for( unsigned i = 0; i < i_count; i++ )
429 p_sys->pi_order[i] = -1;
431 for( unsigned c = 0; c < i_count; )
433 unsigned i = ((unsigned)vlc_mrand48()) % i_count;
434 if( p_sys->pi_order[i] == -1 )
435 p_sys->pi_order[i] = c++;
437 p_sys->b_finished = IsFinished( p_sys );
439 } while( p_sys->b_finished || !IsValid( p_sys ) );
441 if( p_sys->b_blackslot )
443 for( unsigned i = 0; i < i_count; i++ )
445 if( p_sys->pi_order[i] == i_count - 1 )
447 p_sys->i_selected = i;
448 break;
452 else
454 p_sys->i_selected = -1;