1 /*****************************************************************************
2  * puzzle_mgt.c : Puzzle game filter - game management
3  *****************************************************************************
4  * Copyright (C) 2005-2009 VLC authors and VideoLAN
5  * Copyright (C) 2013      Vianney Boyer
6  * $Id: 2e085e8d8098b58a73f2c2ab94050e528f1c1bcf $
7  *
8  * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
9  *          Vianney Boyer <vlcvboyer -at- gmail -dot- com>
10  *
11  * This program is free software; you can redistribute it and/or modify it
12  * under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation; either version 2.1 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25 
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33 #include <math.h>
34 
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_filter.h>
38 #include <vlc_picture.h>
39 #include <vlc_rand.h>
40 
41 #include "filter_picture.h"
42 
43 #include "puzzle_bezier.h"
44 #include "puzzle_lib.h"
45 #include "puzzle_pce.h"
46 #include "puzzle_mgt.h"
47 
48 /*****************************************************************************
49  * puzzle_bake: compute general puzzle data and allocate structures
50  *****************************************************************************/
puzzle_bake(filter_t * p_filter,picture_t * p_pic_out,picture_t * p_pic_in)51 int puzzle_bake( filter_t *p_filter, picture_t *p_pic_out, picture_t *p_pic_in)
52 {
53     filter_sys_t *p_sys = p_filter->p_sys;
54     int i_ret = 0;
55 
56     puzzle_free_ps_puzzle_array ( p_filter );
57     puzzle_free_ps_pieces_shapes ( p_filter);
58     puzzle_free_ps_pieces ( p_filter );
59 
60     p_sys->s_allocated.i_rows =          p_sys->s_current_param.i_rows;
61     p_sys->s_allocated.i_cols =          p_sys->s_current_param.i_cols;
62     p_sys->s_allocated.i_planes =        p_sys->s_current_param.i_planes;
63     p_sys->s_allocated.i_piece_types =   ((p_sys->s_current_param.b_advanced)?PIECE_TYPE_NBR:0);
64     p_sys->s_allocated.i_pieces_nbr =    p_sys->s_allocated.i_rows * p_sys->s_allocated.i_cols;
65     p_sys->s_allocated.b_preview =       p_sys->s_current_param.b_preview;
66     p_sys->s_allocated.i_preview_size =  p_sys->s_current_param.i_preview_size;
67     p_sys->s_allocated.i_border =        p_sys->s_current_param.i_border;
68     p_sys->s_allocated.b_blackslot =     p_sys->s_current_param.b_blackslot;
69     p_sys->s_allocated.b_near =          p_sys->s_current_param.b_near;
70     p_sys->s_allocated.i_shape_size =    p_sys->s_current_param.i_shape_size;
71     p_sys->s_allocated.b_advanced =      p_sys->s_current_param.b_advanced;
72     p_sys->s_allocated.i_auto_shuffle_speed = p_sys->s_current_param.i_auto_shuffle_speed;
73     p_sys->s_allocated.i_auto_solve_speed =   p_sys->s_current_param.i_auto_solve_speed;
74     p_sys->s_allocated.i_rotate =        p_sys->s_current_param.i_rotate;
75 
76     p_sys->ps_puzzle_array = malloc( sizeof( puzzle_array_t** ) * (p_sys->s_allocated.i_rows + 1));
77     if( !p_sys->ps_puzzle_array )
78         return VLC_ENOMEM;
79 
80     for (int32_t r=0; r < p_sys->s_allocated.i_rows + 1; r++) {
81         p_sys->ps_puzzle_array[r] = malloc( sizeof( puzzle_array_t* ) * (p_sys->s_allocated.i_cols + 1));
82         if( !p_sys->ps_puzzle_array[r] )
83             return VLC_ENOMEM;
84         for (int32_t c=0; c < p_sys->s_allocated.i_cols + 1; c++) {
85             p_sys->ps_puzzle_array[r][c] = malloc( sizeof( puzzle_array_t ) * p_sys->s_allocated.i_planes);
86             if( !p_sys->ps_puzzle_array[r][c] )
87                 return VLC_ENOMEM;
88         }
89     }
90 
91     p_sys->ps_desk_planes = malloc( sizeof( puzzle_plane_t ) * p_sys->s_allocated.i_planes);
92     if( !p_sys->ps_desk_planes )
93         return VLC_ENOMEM;
94     p_sys->ps_pict_planes = malloc( sizeof( puzzle_plane_t ) * p_sys->s_allocated.i_planes);
95     if( !p_sys->ps_pict_planes )
96         return VLC_ENOMEM;
97 
98     for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) {
99         p_sys->ps_desk_planes[i_plane].i_lines = p_pic_out->p[i_plane].i_visible_lines;
100         p_sys->ps_desk_planes[i_plane].i_pitch = p_pic_out->p[i_plane].i_pitch;
101         p_sys->ps_desk_planes[i_plane].i_visible_pitch = p_pic_out->p[i_plane].i_visible_pitch;
102         p_sys->ps_desk_planes[i_plane].i_pixel_pitch = p_pic_out->p[i_plane].i_pixel_pitch;
103         p_sys->ps_desk_planes[i_plane].i_width = p_pic_out->p[i_plane].i_visible_pitch / p_pic_out->p[i_plane].i_pixel_pitch;
104 
105         p_sys->ps_desk_planes[i_plane].i_preview_width = p_sys->ps_desk_planes[i_plane].i_width * p_sys->s_current_param.i_preview_size / 100;
106         p_sys->ps_desk_planes[i_plane].i_preview_lines = p_sys->ps_desk_planes[i_plane].i_lines * p_sys->s_current_param.i_preview_size / 100;
107 
108         p_sys->ps_desk_planes[i_plane].i_border_width = p_sys->ps_desk_planes[i_plane].i_width * p_sys->s_current_param.i_border / 2 / 100;
109         p_sys->ps_desk_planes[i_plane].i_border_lines = p_sys->ps_desk_planes[i_plane].i_lines * p_sys->s_current_param.i_border / 2 / 100;
110 
111         p_sys->ps_desk_planes[i_plane].i_pce_max_width = (( p_sys->ps_desk_planes[i_plane].i_width
112                 - 2 * p_sys->ps_desk_planes[i_plane].i_border_width ) + p_sys->s_allocated.i_cols - 1 ) / p_sys->s_allocated.i_cols;
113         p_sys->ps_desk_planes[i_plane].i_pce_max_lines = (( p_sys->ps_desk_planes[i_plane].i_lines
114                 - 2 * p_sys->ps_desk_planes[i_plane].i_border_lines ) + p_sys->s_allocated.i_rows - 1 ) / p_sys->s_allocated.i_rows;
115 
116         p_sys->ps_pict_planes[i_plane].i_lines = p_pic_in->p[i_plane].i_visible_lines;
117         p_sys->ps_pict_planes[i_plane].i_pitch = p_pic_in->p[i_plane].i_pitch;
118         p_sys->ps_pict_planes[i_plane].i_visible_pitch = p_pic_in->p[i_plane].i_visible_pitch;
119         p_sys->ps_pict_planes[i_plane].i_pixel_pitch = p_pic_in->p[i_plane].i_pixel_pitch;
120         p_sys->ps_pict_planes[i_plane].i_width = p_pic_in->p[i_plane].i_visible_pitch / p_pic_in->p[i_plane].i_pixel_pitch;
121 
122         p_sys->ps_pict_planes[i_plane].i_preview_width = p_sys->ps_pict_planes[i_plane].i_width * p_sys->s_current_param.i_preview_size / 100;
123         p_sys->ps_pict_planes[i_plane].i_preview_lines = p_sys->ps_pict_planes[i_plane].i_lines * p_sys->s_current_param.i_preview_size / 100;
124 
125         p_sys->ps_pict_planes[i_plane].i_border_width = p_sys->ps_pict_planes[i_plane].i_width * p_sys->s_current_param.i_border / 2 / 100;
126         p_sys->ps_pict_planes[i_plane].i_border_lines = p_sys->ps_pict_planes[i_plane].i_lines * p_sys->s_current_param.i_border / 2 / 100;
127 
128         p_sys->ps_pict_planes[i_plane].i_pce_max_width = (( p_sys->ps_desk_planes[i_plane].i_width
129                 - 2 * p_sys->ps_pict_planes[i_plane].i_border_width ) + p_sys->s_allocated.i_cols - 1 ) / p_sys->s_allocated.i_cols;
130         p_sys->ps_pict_planes[i_plane].i_pce_max_lines = (( p_sys->ps_pict_planes[i_plane].i_lines
131                 - 2 * p_sys->ps_pict_planes[i_plane].i_border_lines ) + p_sys->s_allocated.i_rows - 1 ) / p_sys->s_allocated.i_rows;
132 
133         for (int32_t r = 0; r < p_sys->s_allocated.i_rows; r++)
134             for (int32_t c = 0; c < p_sys->s_allocated.i_cols; c++) {
135                 if ( r == 0 )
136                     p_sys->ps_puzzle_array[r][c][i_plane].i_y = p_sys->ps_pict_planes[i_plane].i_border_lines;
137                 if ( c == 0 )
138                     p_sys->ps_puzzle_array[r][c][i_plane].i_x = p_sys->ps_pict_planes[i_plane].i_border_width;
139                 p_sys->ps_puzzle_array[r][c][i_plane].i_width =
140                     (p_sys->ps_pict_planes[i_plane].i_width - p_sys->ps_pict_planes[i_plane].i_border_width
141                     - p_sys->ps_puzzle_array[r][c][i_plane].i_x) / ( p_sys->s_allocated.i_cols - c );
142                 p_sys->ps_puzzle_array[r][c][i_plane].i_lines =
143                     (p_sys->ps_pict_planes[i_plane].i_lines - p_sys->ps_pict_planes[i_plane].i_border_lines
144                     - p_sys->ps_puzzle_array[r][c][i_plane].i_y) / ( p_sys->s_allocated.i_rows - r );
145                 p_sys->ps_puzzle_array[r][c + 1][i_plane].i_x =
146                     p_sys->ps_puzzle_array[r][c][i_plane].i_x + p_sys->ps_puzzle_array[r][c][i_plane].i_width;
147                 p_sys->ps_puzzle_array[r + 1][c][i_plane].i_y =
148                     p_sys->ps_puzzle_array[r][c][i_plane].i_y + p_sys->ps_puzzle_array[r][c][i_plane].i_lines;
149             }
150     }
151 
152     p_sys->i_magnet_accuracy = ( p_sys->s_current_param.i_pict_width / 50) + 3;
153 
154     if (p_sys->s_current_param.b_advanced && p_sys->s_allocated.i_shape_size != 0) {
155         i_ret = puzzle_bake_pieces_shapes ( p_filter );
156         if (i_ret != VLC_SUCCESS)
157             return i_ret;
158     }
159 
160     i_ret = puzzle_bake_piece ( p_filter );
161     if (i_ret != VLC_SUCCESS)
162         return i_ret;
163 
164     if ( (p_sys->pi_order != NULL) && (p_sys->ps_desk_planes != NULL) && (p_sys->ps_pict_planes != NULL)
165         && (p_sys->ps_puzzle_array != NULL) && (p_sys->ps_pieces != NULL) )
166         p_sys->b_init = true;
167 
168     if ( (p_sys->ps_pieces_shapes == NULL) && (p_sys->s_current_param.b_advanced)
169         && (p_sys->s_current_param.i_shape_size != 0) )
170         p_sys->b_init = false;
171 
172     return VLC_SUCCESS;
173 }
174 
puzzle_free_ps_puzzle_array(filter_t * p_filter)175 void puzzle_free_ps_puzzle_array( filter_t *p_filter)
176 {
177     filter_sys_t *p_sys = p_filter->p_sys;
178 
179     if (p_sys->ps_puzzle_array != NULL) {
180         for (int32_t r=0; r < p_sys->s_allocated.i_rows + 1; r++) {
181             for (int32_t c=0; c < p_sys->s_allocated.i_cols + 1; c++)
182                 free( p_sys->ps_puzzle_array[r][c] );
183             free( p_sys->ps_puzzle_array[r] );
184         }
185         free( p_sys->ps_puzzle_array );
186     }
187     p_sys->ps_puzzle_array = NULL;
188 
189     free ( p_sys->ps_desk_planes );
190     p_sys->ps_desk_planes = NULL;
191 
192     free ( p_sys->ps_pict_planes );
193     p_sys->ps_pict_planes = NULL;
194 
195     return;
196 }
197 
198 /*****************************************************************************
199  * puzzle_bake_piece: compute data dedicated to each piece
200  *****************************************************************************/
puzzle_bake_piece(filter_t * p_filter)201 int puzzle_bake_piece( filter_t *p_filter)
202 {
203     int i_ret = puzzle_allocate_ps_pieces( p_filter);
204     if (i_ret != VLC_SUCCESS)
205         return i_ret;
206 
207     filter_sys_t *p_sys = p_filter->p_sys;
208 
209     /* generates random pi_order array */
210     i_ret = puzzle_shuffle( p_filter );
211     if (i_ret != VLC_SUCCESS)
212         return i_ret;
213 
214     int32_t i = 0;
215     for (int32_t row = 0; row < p_sys->s_allocated.i_rows; row++) {
216         for (int32_t col = 0; col < p_sys->s_allocated.i_cols; col++) {
217             int32_t orow = row;
218             int32_t ocol = col;
219 
220             if (p_sys->pi_order != NULL) {
221                 orow = p_sys->pi_order[i] / (p_sys->s_allocated.i_cols);
222                 ocol = p_sys->pi_order[i] % (p_sys->s_allocated.i_cols);
223             }
224 
225             p_sys->ps_pieces[i].i_original_row = orow;
226             p_sys->ps_pieces[i].i_original_col = ocol;
227 
228             /* set bottom and right shapes */
229             p_sys->ps_pieces[i].i_left_shape  = 0;
230             p_sys->ps_pieces[i].i_top_shape   = 2;
231             p_sys->ps_pieces[i].i_btm_shape   = 4;
232             p_sys->ps_pieces[i].i_right_shape = 6;
233 
234             if (p_sys->s_allocated.i_shape_size > 0) {
235 
236                 if (orow < p_sys->s_allocated.i_rows - 1)
237                     p_sys->ps_pieces[i].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
238 
239                 if (ocol < p_sys->s_allocated.i_cols - 1)
240                     p_sys->ps_pieces[i].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
241             }
242 
243             /* set piece data */
244             p_sys->ps_pieces[i].i_actual_angle   = 0;
245             p_sys->ps_pieces[i].b_overlap        = false;
246             p_sys->ps_pieces[i].i_actual_mirror  = +1;
247             p_sys->ps_pieces[i].b_finished       = ((ocol == col) && (orow == row));
248             p_sys->ps_pieces[i].i_group_ID       = i;
249 
250             /* add small random offset to location */
251             int32_t i_rand_x = 0;
252             int32_t i_rand_y = 0;
253             if (p_sys->s_current_param.b_advanced) {
254                 i_rand_x = (( (unsigned) vlc_mrand48()) % ( p_sys->ps_desk_planes[0].i_pce_max_width + 1 ) ) - (int32_t) p_sys->ps_desk_planes[0].i_pce_max_width / 2;
255                 i_rand_y = (( (unsigned) vlc_mrand48()) % ( p_sys->ps_desk_planes[0].i_pce_max_lines + 1 ) ) - (int32_t) p_sys->ps_desk_planes[0].i_pce_max_lines / 2;
256             }
257 
258             /* copy related puzzle data to piece data */
259             if (p_sys->ps_puzzle_array != NULL) {
260                 for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) {
261 
262                     p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_width = p_sys->ps_puzzle_array[row][col][i_plane].i_width;
263                     p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_lines = p_sys->ps_puzzle_array[row][col][i_plane].i_lines;
264                     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;
265                     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;
266                     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 *
267                         p_sys->ps_desk_planes[i_plane].i_width / p_sys->ps_desk_planes[0].i_width;
268                     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 *
269                         p_sys->ps_desk_planes[i_plane].i_lines / p_sys->ps_desk_planes[0].i_lines;
270 
271                     if (i_plane == 0) {
272 
273                         p_sys->ps_pieces[i].i_OLx = p_sys->ps_pieces[i].ps_piece_in_plane[0].i_original_x;
274                         p_sys->ps_pieces[i].i_OTy = p_sys->ps_pieces[i].ps_piece_in_plane[0].i_original_y;
275                         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_width - 1;
276                         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_lines - 1;
277 
278                         puzzle_calculate_corners( p_filter, i );
279                     }
280                 }
281             }
282             i++;
283         }
284     }
285 
286     /* left and top shapes are based on negative right and bottom ones */
287     puzzle_set_left_top_shapes( p_filter);
288 
289     /* add random rotation to each piece */
290     puzzle_random_rotate( p_filter);
291 
292     return VLC_SUCCESS;
293 }
294 
295 /*****************************************************************************
296  * puzzle_set_left_top_shapes: Set the shape ID to be used for top and left
297  *                             edges of each piece. Those ID will be set to
298  *                             be the negative of bottom or right of adjacent
299  *                             piece.
300  *****************************************************************************/
puzzle_set_left_top_shapes(filter_t * p_filter)301 void puzzle_set_left_top_shapes( filter_t *p_filter)
302 {
303     filter_sys_t *p_sys = p_filter->p_sys;
304     /* for each piece on the desk... */
305     for (uint16_t i_pce_B=0; i_pce_B < p_sys->s_allocated.i_pieces_nbr; i_pce_B++)
306         /* ...search adjacent piece */
307         for (uint16_t i_pce_A=0;     i_pce_A < p_sys->s_allocated.i_pieces_nbr; i_pce_A++)
308         {
309             if (     ( p_sys->ps_pieces[i_pce_A].i_original_row == p_sys->ps_pieces[i_pce_B].i_original_row )
310                   && ( p_sys->ps_pieces[i_pce_A].i_original_col == p_sys->ps_pieces[i_pce_B].i_original_col-1 ) )
311                 /* left shape is based on negative (invert ID LSB) right one */
312                 p_sys->ps_pieces[i_pce_B].i_left_shape = (p_sys->ps_pieces[i_pce_A].i_right_shape - 6 ) ^ 0x01;
313 
314             if (     ( p_sys->ps_pieces[i_pce_A].i_original_row == p_sys->ps_pieces[i_pce_B].i_original_row - 1 )
315                   && ( p_sys->ps_pieces[i_pce_A].i_original_col == p_sys->ps_pieces[i_pce_B].i_original_col ) )
316                 /* top shape is based on negative of bottom one
317                  *                 top ID = bottom ID - 2
318                  *                 negative ID = invert LSB
319                  */
320                 p_sys->ps_pieces[i_pce_B].i_top_shape = (p_sys->ps_pieces[i_pce_A].i_btm_shape - 2 ) ^ 0x01;
321         }
322 }
323 
puzzle_random_rotate(filter_t * p_filter)324 void puzzle_random_rotate( filter_t *p_filter)
325 {
326     filter_sys_t *p_sys = p_filter->p_sys;
327     /* add random rotation to each piece */
328     for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++)
329     {
330         p_sys->ps_pieces[i].i_actual_angle  = 0;
331         p_sys->ps_pieces[i].i_actual_mirror = +1;
332 
333         switch ( p_sys->s_current_param.i_rotate )
334         {
335           case 1:
336                 puzzle_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 );
337             break;
338           case 2:
339                 puzzle_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 );
340             break;
341           case 3:
342                 puzzle_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 );
343             break;
344         }
345         puzzle_calculate_corners( p_filter, i );
346     }
347 }
348 
puzzle_free_ps_pieces(filter_t * p_filter)349 void puzzle_free_ps_pieces( filter_t *p_filter)
350 {
351     filter_sys_t *p_sys = p_filter->p_sys;
352 
353     if (p_sys->ps_pieces != NULL) {
354         for (uint32_t i_pce = 0; i_pce < p_sys->s_allocated.i_pieces_nbr; i_pce++)
355             free( p_sys->ps_pieces[i_pce].ps_piece_in_plane );
356         free( p_sys->ps_pieces );
357     }
358     p_sys->ps_pieces = NULL;
359 
360     free( p_sys->pi_order );
361     p_sys->pi_order = NULL;
362 
363     free( p_sys->ps_pieces_tmp );
364     p_sys->ps_pieces_tmp = NULL;
365 
366     free( p_sys->pi_group_qty );
367     p_sys->pi_group_qty = NULL;
368 
369     return;
370 }
371 
puzzle_allocate_ps_pieces(filter_t * p_filter)372 int puzzle_allocate_ps_pieces( filter_t *p_filter)
373 {
374     filter_sys_t *p_sys = p_filter->p_sys;
375     puzzle_free_ps_pieces(p_filter);
376     p_sys->s_allocated.i_pieces_nbr = p_sys->s_allocated.i_rows * p_sys->s_allocated.i_cols;
377     p_sys->ps_pieces = malloc( sizeof( piece_t) * p_sys->s_allocated.i_pieces_nbr );
378     if( !p_sys->ps_pieces )
379         return VLC_ENOMEM;
380     for (uint32_t p = 0; p < p_sys->s_allocated.i_pieces_nbr; p++) {
381         p_sys->ps_pieces[p].ps_piece_in_plane = malloc( sizeof( piece_in_plane_t) * p_sys->s_allocated.i_planes );
382         if( !p_sys->ps_pieces[p].ps_piece_in_plane ) {
383             for (uint32_t i=0;i<p;i++)
384                 free(p_sys->ps_pieces[i].ps_piece_in_plane);
385             free(p_sys->ps_pieces);
386             p_sys->ps_pieces = NULL;
387             return VLC_ENOMEM;
388         }
389     }
390 
391     p_sys->ps_pieces_tmp = malloc( sizeof( piece_t) * p_sys->s_allocated.i_pieces_nbr );
392     if( !p_sys->ps_pieces_tmp ) {
393         for (uint32_t i=0;i<p_sys->s_allocated.i_pieces_nbr;i++)
394             free(p_sys->ps_pieces[i].ps_piece_in_plane);
395         free(p_sys->ps_pieces);
396         p_sys->ps_pieces = NULL;
397         return VLC_ENOMEM;
398     }
399     p_sys->pi_group_qty = malloc( sizeof( int32_t ) * (p_sys->s_allocated.i_pieces_nbr));
400     if( !p_sys->pi_group_qty ) {
401         for (uint32_t i=0;i<p_sys->s_allocated.i_pieces_nbr;i++)
402             free(p_sys->ps_pieces[i].ps_piece_in_plane);
403         free(p_sys->ps_pieces);
404         p_sys->ps_pieces = NULL;
405         free(p_sys->ps_pieces_tmp);
406         p_sys->ps_pieces_tmp = NULL;
407         return VLC_ENOMEM;
408     }
409     return VLC_SUCCESS;
410 }
411 
puzzle_is_valid(filter_sys_t * p_sys,int32_t * pi_pce_lst)412 bool puzzle_is_valid( filter_sys_t *p_sys, int32_t *pi_pce_lst )
413 {
414     const int32_t i_count = p_sys->s_allocated.i_pieces_nbr;
415 
416     if( !p_sys->s_current_param.b_blackslot )
417         return true;
418 
419     int32_t d = 0;
420     for( int32_t i = 0; i < i_count; i++ ) {
421         if( pi_pce_lst[i] == i_count - 1 ) {
422             d += i / p_sys->s_allocated.i_cols + 1;
423             continue;
424         }
425         for( int32_t j = i+1; j < i_count; j++ ) {
426             if( pi_pce_lst[j] == i_count - 1 )
427                 continue;
428             if( pi_pce_lst[i] > pi_pce_lst[j] )
429                 d++;
430         }
431     }
432     return (d%2) == 0;
433 }
434 
puzzle_shuffle(filter_t * p_filter)435 int puzzle_shuffle( filter_t *p_filter )
436 {
437     filter_sys_t *p_sys = p_filter->p_sys;
438 
439     int32_t i_pieces_nbr = p_sys->s_allocated.i_pieces_nbr;
440 
441     do
442     {
443         int i_ret = puzzle_generate_rand_pce_list( p_filter, &p_sys->pi_order );
444         if (i_ret != VLC_SUCCESS)
445             return i_ret;
446     } while( puzzle_is_finished( p_sys, p_sys->pi_order ) || !puzzle_is_valid( p_sys, p_sys->pi_order ) );
447 
448 
449     if( p_sys->s_current_param.b_blackslot ) {
450         for( int32_t i = 0; i < i_pieces_nbr; i++ )
451             if( p_sys->pi_order[i] == i_pieces_nbr - 1 ) {
452                 p_sys->i_selected = i;
453                 break;
454             }
455     }
456     else {
457         p_sys->i_selected = NO_PCE;
458     }
459 
460     p_sys->b_shuffle_rqst = false;
461     p_sys->b_finished = false;
462 
463     return VLC_SUCCESS;
464 }
465 
puzzle_generate_rand_pce_list(filter_t * p_filter,int32_t ** pi_pce_lst)466 int puzzle_generate_rand_pce_list( filter_t *p_filter, int32_t **pi_pce_lst )
467 {
468     filter_sys_t *p_sys = p_filter->p_sys;
469     int32_t i_pieces_nbr = p_sys->s_allocated.i_pieces_nbr;
470 
471     free( *pi_pce_lst );
472     *pi_pce_lst = calloc( i_pieces_nbr, sizeof(**pi_pce_lst) );
473     if( !*pi_pce_lst )
474         return VLC_ENOMEM;
475 
476     for( int32_t i = 0; i < i_pieces_nbr; i++ )
477         (*pi_pce_lst)[i] = NO_PCE;
478 
479     for( int32_t c = 0; c < i_pieces_nbr; ) {
480         int32_t i = ((unsigned)vlc_mrand48()) % i_pieces_nbr;
481         if( (*pi_pce_lst)[i] == NO_PCE )
482             (*pi_pce_lst)[i] = c++;
483     }
484     return VLC_SUCCESS;
485 }
486 
puzzle_is_finished(filter_sys_t * p_sys,int32_t * pi_pce_lst)487 bool puzzle_is_finished( filter_sys_t *p_sys, int32_t *pi_pce_lst )
488 {
489     for( uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++ )
490         if( (int32_t)i != pi_pce_lst[i] )
491             return false;
492 
493     return true;
494 }
495 
puzzle_piece_foreground(filter_t * p_filter,int32_t i_piece)496 int puzzle_piece_foreground( filter_t *p_filter, int32_t i_piece) {
497     filter_sys_t *p_sys = p_filter->p_sys;
498     piece_t *ps_pieces_tmp;        /* list [piece] of pieces data. Sort as per layers */
499     uint32_t i_group_ID = p_sys->ps_pieces[i_piece].i_group_ID;
500 
501     ps_pieces_tmp = malloc( sizeof( piece_t) * p_sys->s_allocated.i_pieces_nbr );
502     if (!ps_pieces_tmp)
503         return VLC_ENOMEM;
504 
505     int32_t j=0;
506 
507     memcpy( &ps_pieces_tmp[j], &p_sys->ps_pieces[i_piece], sizeof(piece_t) );
508     j++;
509 
510     for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
511         if ( ( p_sys->ps_pieces[i].i_group_ID == i_group_ID ) && ( (int32_t)i != i_piece ) ) {
512             memcpy( &ps_pieces_tmp[j], &p_sys->ps_pieces[i], sizeof(piece_t));
513             j++;
514         }
515     }
516     for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
517         if ( p_sys->ps_pieces[i].i_group_ID != i_group_ID ) {
518             memcpy( &ps_pieces_tmp[j], &p_sys->ps_pieces[i], sizeof(piece_t));
519             j++;
520         }
521     }
522 
523     free( p_filter->p_sys->ps_pieces );
524     p_filter->p_sys->ps_pieces = ps_pieces_tmp;
525 
526     return VLC_SUCCESS;
527 }
528 
puzzle_count_pce_group(filter_t * p_filter)529 void puzzle_count_pce_group( filter_t *p_filter) { /* count pce in each group */
530     filter_sys_t *p_sys = p_filter->p_sys;
531 
532     memset ( p_sys->pi_group_qty, 0, sizeof( int32_t ) * (p_sys->s_allocated.i_pieces_nbr) );
533     for (uint32_t i_pce = 0; i_pce < p_sys->s_allocated.i_pieces_nbr; i_pce++)
534         p_sys->pi_group_qty[p_sys->ps_pieces[i_pce].i_group_ID]++;
535 }
536 
537 /*****************************************************************************
538  * puzzle_solve_pces_group: check if pieces are close together
539  *                          and then combine in a group
540  *****************************************************************************/
puzzle_solve_pces_group(filter_t * p_filter)541 void puzzle_solve_pces_group( filter_t *p_filter) {
542     filter_sys_t *p_sys = p_filter->p_sys;
543     int32_t i_dx, i_dy;
544 
545     p_sys->i_solve_grp_loop++;
546     p_sys->i_solve_grp_loop %= p_sys->s_allocated.i_pieces_nbr;
547 
548     int32_t i_piece_A = p_sys->i_solve_grp_loop;
549     piece_t *ps_piece_A = &p_sys->ps_pieces[i_piece_A];
550 
551     for (uint32_t i_piece_B = 0; i_piece_B < p_sys->s_allocated.i_pieces_nbr; i_piece_B++)
552     {
553         piece_t *ps_piece_B = &p_sys->ps_pieces[i_piece_B];
554 
555         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 )
556             continue;
557 
558         if ( (ps_piece_B->i_group_ID != p_sys->ps_pieces[i_piece_A].i_group_ID ) )
559         {
560             if ( abs(ps_piece_A->i_OTy - ps_piece_B->i_OTy )<3)
561             {
562                 if (    abs( ps_piece_A->i_ORx - ps_piece_B->i_OLx + 1 ) < 3
563                      && abs( ps_piece_A->i_TRx - ps_piece_B->i_TLx + 1 ) < p_sys->i_magnet_accuracy
564                      && abs( ps_piece_A->i_TRy - ps_piece_B->i_TLy ) < p_sys->i_magnet_accuracy
565                      && abs( ps_piece_A->i_BRx - ps_piece_B->i_BLx + 1 ) < p_sys->i_magnet_accuracy
566                      && abs( ps_piece_A->i_BRy - ps_piece_B->i_BLy ) < p_sys->i_magnet_accuracy )
567                 {
568                     i_dx = ps_piece_A->i_TRx - ps_piece_B->i_TLx + ps_piece_A->i_step_x_x;
569                     i_dy = ps_piece_A->i_TRy - ps_piece_B->i_TLy;
570 
571                     if (!ps_piece_B->b_finished)
572                         puzzle_move_group( p_filter, i_piece_B, i_dx, i_dy);
573                     else
574                         puzzle_move_group( p_filter, i_piece_A, -i_dx, -i_dy);
575 
576                     uint32_t i_group_ID = ps_piece_B->i_group_ID;
577                     for (uint32_t i_for = 0; i_for < p_sys->s_allocated.i_pieces_nbr; i_for++)
578                         if ( p_sys->ps_pieces[i_for].i_group_ID == i_group_ID)
579                             p_sys->ps_pieces[i_for].i_group_ID = p_sys->ps_pieces[i_piece_A].i_group_ID;
580                 }
581             }
582             else if ( abs(ps_piece_A->i_OLx - ps_piece_B->i_OLx ) < 3 )
583             {
584                 if (    abs(ps_piece_A->i_OBy - ps_piece_B->i_OTy + 1 ) < 3
585                      && abs( ps_piece_B->i_TLx - ps_piece_A->i_BLx ) < p_sys->i_magnet_accuracy
586                      && abs( ps_piece_B->i_TLy - 1 - ps_piece_A->i_BLy ) < p_sys->i_magnet_accuracy
587                      && abs( ps_piece_B->i_TRx - ps_piece_A->i_BRx ) < p_sys->i_magnet_accuracy
588                      && abs( ps_piece_B->i_TRy - 1 - ps_piece_A->i_BRy ) < p_sys->i_magnet_accuracy )
589                 {
590 
591                     i_dx = ps_piece_A->i_BLx - ps_piece_B->i_TLx;
592                     i_dy = ps_piece_A->i_BLy - ps_piece_B->i_TLy + ps_piece_A->i_step_y_y;
593 
594                     if (!ps_piece_B->b_finished)
595                         puzzle_move_group( p_filter, i_piece_B, i_dx, i_dy);
596                     else
597                         puzzle_move_group( p_filter, i_piece_A, -i_dx, -i_dy);
598 
599                     uint32_t i_group_ID = ps_piece_B->i_group_ID;
600                     for (uint32_t i_for = 0; i_for < p_sys->s_allocated.i_pieces_nbr; i_for++)
601                         if ( p_sys->ps_pieces[i_for].i_group_ID == i_group_ID)
602                             p_sys->ps_pieces[i_for].i_group_ID = p_sys->ps_pieces[i_piece_A].i_group_ID;
603                 }
604             }
605         }
606 
607         if ( abs( ps_piece_A->i_OTy - ps_piece_B->i_OTy ) < 3 )
608         {
609             if (    abs( ps_piece_A->i_ORx - ps_piece_B->i_OLx + 1 ) < 3
610                  && abs( ps_piece_A->i_TRx - ps_piece_B->i_TLx + 1 ) < p_sys->i_magnet_accuracy
611                  && abs( ps_piece_A->i_TRy - ps_piece_B->i_TLy ) < p_sys->i_magnet_accuracy
612                  && abs( ps_piece_A->i_BRx - ps_piece_B->i_BLx + 1 ) < p_sys->i_magnet_accuracy
613                  && abs( ps_piece_A->i_BRy - ps_piece_B->i_BLy ) < p_sys->i_magnet_accuracy )
614             {
615                 ps_piece_B->i_left_shape = 0;
616                 ps_piece_A->i_right_shape = 6;
617             }
618         }
619         else if ( abs( ps_piece_A->i_OLx - ps_piece_B->i_OLx )<3 )
620         {
621             if (    abs( ps_piece_A->i_OBy - ps_piece_B->i_OTy + 1 )<3
622                  && abs( ps_piece_B->i_TLx - ps_piece_A->i_BLx ) < p_sys->i_magnet_accuracy
623                  && abs( ps_piece_B->i_TLy - 1 - ps_piece_A->i_BLy ) < p_sys->i_magnet_accuracy
624                  && abs( ps_piece_B->i_TRx - ps_piece_A->i_BRx ) < p_sys->i_magnet_accuracy
625                  && abs( ps_piece_B->i_TRy - 1 - ps_piece_A->i_BRy ) < p_sys->i_magnet_accuracy )
626             {
627                 ps_piece_B->i_top_shape = 2;
628                 ps_piece_A->i_btm_shape = 4;
629             }
630         }
631    }
632 }
633 
634 /*****************************************************************************
635  * puzzle_solve_pces_accuracy: check if pieces are close to their final location
636  *                             and then adjust position accordingly
637  *****************************************************************************/
puzzle_solve_pces_accuracy(filter_t * p_filter)638 void puzzle_solve_pces_accuracy( filter_t *p_filter) {
639     filter_sys_t *p_sys = p_filter->p_sys;
640 
641     p_sys->i_solve_acc_loop++;
642     if (p_sys->i_solve_acc_loop >= p_sys->s_allocated.i_pieces_nbr) {
643         p_sys->i_done_count = p_sys->i_tmp_done_count;
644         p_sys->i_tmp_done_count = 0;
645         p_sys->i_solve_acc_loop = 0;
646         p_sys->b_finished = (p_sys->i_done_count == p_sys->s_allocated.i_pieces_nbr);
647     }
648 
649     piece_t *ps_piece = &p_sys->ps_pieces[p_sys->i_solve_acc_loop];
650 
651     ps_piece->b_finished = false;
652     if (    ps_piece->i_actual_mirror == 1
653          && abs( ps_piece->i_TRx - ps_piece->i_ORx )  < p_sys->i_magnet_accuracy
654          && abs( ps_piece->i_TRy - ps_piece->i_OTy )  < p_sys->i_magnet_accuracy
655          && abs( ps_piece->i_TLx - ps_piece->i_OLx )  < p_sys->i_magnet_accuracy
656          && abs( ps_piece->i_TLy - ps_piece->i_OTy )  < p_sys->i_magnet_accuracy )
657     {
658         uint32_t i_group_ID = ps_piece->i_group_ID;
659         p_sys->i_tmp_done_count++;
660 
661         for ( uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
662             ps_piece = &p_sys->ps_pieces[i];
663             if ( ( ps_piece->i_group_ID == i_group_ID ) && ( !ps_piece->b_finished ) ) {
664                 ps_piece->ps_piece_in_plane[0].i_actual_x = ps_piece->i_OLx;
665                 ps_piece->ps_piece_in_plane[0].i_actual_y = ps_piece->i_OTy;
666                 ps_piece->i_actual_mirror = +1;
667                 puzzle_calculate_corners( p_filter, i );
668                 ps_piece->b_finished = true;
669             }
670         }
671     }
672 }
673 
674 /*****************************************************************************
675  * puzzle_sort_layers: sort pieces in order to see in foreground the
676  *                     standalone ones and those are at the wrong place
677  *****************************************************************************/
puzzle_sort_layers(filter_t * p_filter)678 int puzzle_sort_layers( filter_t *p_filter)
679 {
680     filter_sys_t *p_sys = p_filter->p_sys;
681 
682     int32_t i_idx = 0;
683     for (uint32_t i_qty = 1; i_qty <= p_sys->s_current_param.i_pieces_nbr; i_qty++) {
684         /* pieces at the wrong place are in foreground */
685         for (uint32_t i_pce_loop = 0; i_pce_loop < p_sys->s_current_param.i_pieces_nbr; i_pce_loop++) {
686             uint32_t i_grp = p_sys->ps_pieces[i_pce_loop].i_group_ID;
687             if ( p_sys->pi_group_qty[i_grp] == (int32_t)i_qty ) {
688                 bool b_check_ok = true;
689                 for (int32_t i_pce_check = 0; i_pce_check < i_idx; i_pce_check++)
690                     if ( p_sys->ps_pieces_tmp[i_pce_check].i_group_ID == i_grp )
691                         b_check_ok = false;
692                 if ( b_check_ok )
693                     for (uint32_t i_pce = i_pce_loop; i_pce < p_sys->s_current_param.i_pieces_nbr; i_pce++)
694                         if (( p_sys->ps_pieces[i_pce].i_group_ID == i_grp ) && !p_sys->ps_pieces[i_pce].b_finished ) {
695                             memcpy( &p_sys->ps_pieces_tmp[i_idx], &p_sys->ps_pieces[i_pce], sizeof(piece_t));
696                             i_idx++;
697                         }
698             }
699         }
700         /* pieces at the final location are in background */
701         for (uint32_t i_pce_loop = 0; i_pce_loop < p_sys->s_current_param.i_pieces_nbr; i_pce_loop++) {
702             uint32_t i_grp = p_sys->ps_pieces[i_pce_loop].i_group_ID;
703             if ( p_sys->pi_group_qty[i_grp] == (int32_t)i_qty ) {
704                 bool b_check_ok = true;
705                 for (int32_t i_pce_check = 0; i_pce_check < i_idx; i_pce_check++)
706                     if ( p_sys->ps_pieces_tmp[i_pce_check].i_group_ID == i_grp && p_sys->ps_pieces_tmp[i_pce_check].b_finished )
707                         b_check_ok = false;
708                 if ( b_check_ok )
709                     for (uint32_t i_pce = i_pce_loop; i_pce < p_sys->s_current_param.i_pieces_nbr; i_pce++)
710                         if (( p_sys->ps_pieces[i_pce].i_group_ID == i_grp ) && p_sys->ps_pieces[i_pce].b_finished ) {
711                             memcpy( &p_sys->ps_pieces_tmp[i_idx], &p_sys->ps_pieces[i_pce], sizeof(piece_t));
712                             i_idx++;
713                         }
714             }
715         }
716     }
717 
718     free( p_filter->p_sys->ps_pieces );
719     p_filter->p_sys->ps_pieces = p_sys->ps_pieces_tmp;
720     p_sys->ps_pieces_tmp = malloc( sizeof( piece_t) * p_sys->s_allocated.i_pieces_nbr );
721     if (!p_sys->ps_pieces_tmp)
722         return VLC_ENOMEM;
723 
724     return VLC_SUCCESS;
725 }
726 
727 /*****************************************************************************
728  * puzzle_auto_solve: solve the puzzle depending on auto_solve_speed parameter
729  *                    = move one piece at the final location each time
730  *                      auto_solve_countdown is < 0
731  *****************************************************************************/
puzzle_auto_solve(filter_t * p_filter)732 void puzzle_auto_solve( filter_t *p_filter)
733 {
734     filter_sys_t *p_sys = p_filter->p_sys;
735 
736     if ( p_sys->s_current_param.i_auto_solve_speed < 500 )
737         return;
738 
739     if ( --p_sys->i_auto_solve_countdown_val > 0 )
740         return;
741 
742     /* delay reached, preset next delay and proceed with puzzle_auto_solve */
743     p_sys->i_auto_solve_countdown_val = init_countdown(p_sys->s_current_param.i_auto_solve_speed);
744 
745     /* random piece to be moved */
746     int32_t i_start = ((unsigned)vlc_mrand48()) % p_sys->s_allocated.i_pieces_nbr;
747 
748     /* here the computer will help player by placing the piece at the final location */
749     for (uint32_t i_l = 0; i_l < p_sys->s_allocated.i_pieces_nbr; i_l++) {
750         int32_t i = ( i_l + i_start ) % p_sys->s_allocated.i_pieces_nbr;
751         if ( !p_sys->ps_pieces[i].b_finished ) {
752             for (uint32_t j = 0; j < p_sys->s_allocated.i_pieces_nbr; j++) {
753                 if ( p_sys->ps_pieces[j].i_group_ID == p_sys->ps_pieces[i].i_group_ID ) {
754                     p_sys->ps_pieces[j].i_actual_angle   = 0;
755                     p_sys->ps_pieces[j].i_actual_mirror  = +1;
756                     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;
757                     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;
758                     puzzle_calculate_corners( p_filter, j );
759                 }
760             }
761             break;
762         }
763     }
764 }
765 
766 /*****************************************************************************
767  * puzzle_auto_shuffle: shuffle the pieces on the desk depending on
768  *                      auto_shuffle_speed parameter
769  *                    = random move of one piece each time
770  *                      auto_shuffle_countdown is < 0
771  *****************************************************************************/
puzzle_auto_shuffle(filter_t * p_filter)772 void puzzle_auto_shuffle( filter_t *p_filter)
773 {
774     filter_sys_t *p_sys = p_filter->p_sys;
775 
776     if ( p_sys->s_current_param.i_auto_shuffle_speed < 500 )
777         return;
778 
779     if ( --p_sys->i_auto_shuffle_countdown_val > 0 )
780         return;
781 
782     /* delay reached, preset next delay and proceed with puzzle_auto_shuffle */
783     p_sys->i_auto_shuffle_countdown_val = init_countdown(p_sys->s_current_param.i_auto_shuffle_speed);
784 
785     /* random piece to be moved */
786     int32_t i_start = ((unsigned)vlc_mrand48()) % p_sys->s_allocated.i_pieces_nbr;
787 
788     for (uint32_t i_l = 0; i_l < p_sys->s_allocated.i_pieces_nbr; i_l++){
789         int32_t i = ( i_l + i_start ) % p_sys->s_allocated.i_pieces_nbr;
790 
791         /* find one piece which is part of one group */
792         if ( p_sys->pi_group_qty[p_sys->ps_pieces[i].i_group_ID] > 1 ) {
793             /* find an empty group to be used by this dismantled piece */
794             uint32_t i_new_group;
795             for ( i_new_group = 0 ; i_new_group < p_sys->s_allocated.i_pieces_nbr ; i_new_group ++ )
796                 if ( p_sys->pi_group_qty[i_new_group] == 0 )
797                     break;
798             p_sys->ps_pieces[i].i_group_ID = i_new_group;
799             p_sys->ps_pieces[i].b_finished = false;
800 
801             /* random rotate & mirror */
802             switch ( p_sys->s_current_param.i_rotate )
803             {
804               case 1:
805                     puzzle_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 );
806                 break;
807               case 2:
808                     puzzle_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 );
809                 break;
810               case 3:
811                     puzzle_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 );
812                 break;
813             }
814 
815             /* random mvt */
816             p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_x =
817                     p_sys->ps_desk_planes[0].i_border_width
818                     + ( (unsigned) vlc_mrand48()) % ( p_sys->ps_desk_planes[0].i_width - 2*p_sys->ps_desk_planes[0].i_border_width - p_sys->ps_pieces[i].ps_piece_in_plane[0].i_width)
819                     + p_sys->ps_pieces[i].ps_piece_in_plane[0].i_width / 2 * ( 1 - p_sys->ps_pieces[i].i_step_x_x )
820                     - (p_sys->ps_pieces[i].ps_piece_in_plane[0].i_lines / 2) * p_sys->ps_pieces[i].i_step_y_x;
821             p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_y =
822                     p_sys->ps_desk_planes[0].i_border_lines
823                     + ( (unsigned) vlc_mrand48()) % ( p_sys->ps_desk_planes[0].i_lines - 2*p_sys->ps_desk_planes[0].i_border_lines - p_sys->ps_pieces[i].ps_piece_in_plane[0].i_lines)
824                     + p_sys->ps_pieces[i].ps_piece_in_plane[0].i_lines / 2 * ( 1 - p_sys->ps_pieces[i].i_step_y_y )
825                     - (p_sys->ps_pieces[i].ps_piece_in_plane[0].i_width / 2) * p_sys->ps_pieces[i].i_step_x_y;
826 
827             /* redefine shapes */
828             uint32_t i_left_pce  = 0;
829             uint32_t i_right_pce = 6;
830             uint32_t i_top_pce   = 2;
831             uint32_t i_btm_pce   = 4;
832 
833             uint32_t i_pce = 0;
834             for (int32_t i_row = 0; i_row < p_sys->s_allocated.i_rows; i_row++)
835                 for (int32_t i_col = 0; i_col < p_sys->s_allocated.i_cols; i_col++) {
836                     if (p_sys->ps_pieces[i].i_original_row == p_sys->ps_pieces[i_pce].i_original_row) {
837                         if (p_sys->ps_pieces[i].i_original_col == p_sys->ps_pieces[i_pce].i_original_col - 1)
838                             i_right_pce = i_pce;
839                         else if (p_sys->ps_pieces[i].i_original_col == p_sys->ps_pieces[i_pce].i_original_col + 1)
840                             i_left_pce = i_pce;
841                     }
842                     else if (p_sys->ps_pieces[i].i_original_col == p_sys->ps_pieces[i_pce].i_original_col) {
843                         if (p_sys->ps_pieces[i].i_original_row == p_sys->ps_pieces[i_pce].i_original_row - 1)
844                             i_btm_pce = i_pce;
845                         else if (p_sys->ps_pieces[i].i_original_row == p_sys->ps_pieces[i_pce].i_original_row + 1)
846                             i_top_pce = i_pce;
847                     }
848                     i_pce++;
849                 }
850 
851             if ((p_sys->ps_pieces[i].i_left_shape == 0) && (p_sys->ps_pieces[i].i_original_col != 0)) {
852                 p_sys->ps_pieces[i_left_pce].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
853                 p_sys->ps_pieces[i].i_left_shape = (p_sys->ps_pieces[i_left_pce].i_right_shape - 6 ) ^ 0x01;
854             }
855 
856             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)) {
857                 p_sys->ps_pieces[i].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
858                 p_sys->ps_pieces[i_right_pce].i_left_shape = (p_sys->ps_pieces[i].i_right_shape - 6 ) ^ 0x01;
859             }
860 
861             if ((p_sys->ps_pieces[i].i_top_shape == 2) && (p_sys->ps_pieces[i].i_original_row != 0)) {
862                 p_sys->ps_pieces[i_top_pce].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
863                 p_sys->ps_pieces[i].i_top_shape = (p_sys->ps_pieces[i_top_pce].i_btm_shape - 2 ) ^ 0x01;
864             }
865 
866             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)) {
867                 p_sys->ps_pieces[i].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
868                 p_sys->ps_pieces[i_btm_pce].i_top_shape = (p_sys->ps_pieces[i].i_btm_shape - 2 ) ^ 0x01;
869             }
870 
871             puzzle_calculate_corners( p_filter, i );
872             break;
873         }
874     }
875 }
876 
877 /*****************************************************************************
878  * puzzle_save: save pieces location in memory
879  *****************************************************************************/
puzzle_save(filter_t * p_filter)880 save_game_t* puzzle_save(filter_t *p_filter)
881 {
882     filter_sys_t *p_sys = p_filter->p_sys;
883 
884     save_game_t *ps_save_game = calloc(1, sizeof(*ps_save_game));
885     if (!ps_save_game)
886         return NULL;
887 
888     ps_save_game->i_cols   = p_sys->s_allocated.i_cols;
889     ps_save_game->i_rows   = p_sys->s_allocated.i_rows;
890     ps_save_game->i_rotate = p_sys->s_allocated.i_rotate;
891 
892     ps_save_game->ps_pieces = calloc( ps_save_game->i_cols * ps_save_game->i_rows , sizeof(*ps_save_game->ps_pieces));
893     if (!ps_save_game->ps_pieces) {
894         free(ps_save_game);
895         return NULL;
896     }
897 
898     int32_t i_border_width = p_sys->ps_desk_planes[0].i_border_width;
899     int32_t i_border_lines = p_sys->ps_desk_planes[0].i_border_lines;
900 
901     for (int32_t i_pce = 0; i_pce < ps_save_game->i_cols * ps_save_game->i_rows; i_pce++) {
902         ps_save_game->ps_pieces[i_pce].i_original_row  = p_sys->ps_pieces[i_pce].i_original_row;
903         ps_save_game->ps_pieces[i_pce].i_original_col  = p_sys->ps_pieces[i_pce].i_original_col;
904         ps_save_game->ps_pieces[i_pce].i_top_shape     = p_sys->ps_pieces[i_pce].i_top_shape;
905         ps_save_game->ps_pieces[i_pce].i_btm_shape     = p_sys->ps_pieces[i_pce].i_btm_shape;
906         ps_save_game->ps_pieces[i_pce].i_right_shape   = p_sys->ps_pieces[i_pce].i_right_shape;
907         ps_save_game->ps_pieces[i_pce].i_left_shape    = p_sys->ps_pieces[i_pce].i_left_shape;
908         ps_save_game->ps_pieces[i_pce].f_pos_x         =(p_sys->ps_pieces[i_pce].ps_piece_in_plane[0].i_actual_x - i_border_width ) / ((float)p_sys->ps_desk_planes[0].i_width - 2*i_border_width);
909         ps_save_game->ps_pieces[i_pce].f_pos_y         =(p_sys->ps_pieces[i_pce].ps_piece_in_plane[0].i_actual_y - i_border_lines ) / ((float)p_sys->ps_desk_planes[0].i_lines - 2*i_border_lines);
910         ps_save_game->ps_pieces[i_pce].i_actual_angle  = p_sys->ps_pieces[i_pce].i_actual_angle;
911         ps_save_game->ps_pieces[i_pce].i_actual_mirror = p_sys->ps_pieces[i_pce].i_actual_mirror;
912     }
913 
914     return ps_save_game;
915 }
916 
puzzle_load(filter_t * p_filter,save_game_t * ps_save_game)917 void puzzle_load( filter_t *p_filter, save_game_t *ps_save_game)
918 {
919     filter_sys_t *p_sys = p_filter->p_sys;
920 
921     if (p_sys->s_current_param.i_cols  != ps_save_game->i_cols
922         || p_sys->s_allocated.i_rows   != ps_save_game->i_rows
923         || p_sys->s_allocated.i_rotate != ps_save_game->i_rotate)
924         return;
925 
926     int32_t i_border_width = p_sys->ps_desk_planes[0].i_border_width;
927     int32_t i_border_lines = p_sys->ps_desk_planes[0].i_border_lines;
928 
929     for (uint32_t i_pce=0; i_pce < p_sys->s_allocated.i_pieces_nbr; i_pce++) {
930        for (uint32_t i=0; i < p_sys->s_allocated.i_pieces_nbr; i++)
931             if   ( p_sys->ps_pieces[i].i_original_row == ps_save_game->ps_pieces[i_pce].i_original_row
932                 && p_sys->ps_pieces[i].i_original_col == ps_save_game->ps_pieces[i_pce].i_original_col  )
933             {
934                 p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_x = i_border_width
935                         + ((float)p_sys->ps_desk_planes[0].i_width - 2 * i_border_width)
936                         * ps_save_game->ps_pieces[i_pce].f_pos_x;
937                 p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_y = i_border_lines
938                         + ((float)p_sys->ps_desk_planes[0].i_lines - 2 * i_border_lines)
939                         * ps_save_game->ps_pieces[i_pce].f_pos_y;
940 
941                 p_sys->ps_pieces[i].i_top_shape     =  ps_save_game->ps_pieces[i_pce].i_top_shape;
942                 p_sys->ps_pieces[i].i_btm_shape     =  ps_save_game->ps_pieces[i_pce].i_btm_shape;
943                 p_sys->ps_pieces[i].i_right_shape   =  ps_save_game->ps_pieces[i_pce].i_right_shape;
944                 p_sys->ps_pieces[i].i_left_shape    =  ps_save_game->ps_pieces[i_pce].i_left_shape;
945                 p_sys->ps_pieces[i].i_actual_angle  =  ps_save_game->ps_pieces[i_pce].i_actual_angle;
946                 p_sys->ps_pieces[i].i_actual_mirror =  ps_save_game->ps_pieces[i_pce].i_actual_mirror;
947                 p_sys->ps_pieces[i].i_group_ID     = i_pce;
948                 p_sys->ps_pieces[i].b_finished     = false;
949 
950                 p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_x = i_border_width + ((float)p_sys->ps_desk_planes[0].i_width
951                                                                         - 2*i_border_width) * ps_save_game->ps_pieces[i_pce].f_pos_x;
952                 p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_y = i_border_lines + ((float)p_sys->ps_desk_planes[0].i_lines
953                                                                         - 2*i_border_lines) * ps_save_game->ps_pieces[i_pce].f_pos_y;
954                 puzzle_calculate_corners( p_filter, i );
955 
956                 break;
957             }
958     }
959 
960     for (uint32_t i_pce=0; i_pce < p_sys->s_allocated.i_pieces_nbr; i_pce++) {
961         /* redefine shapes */
962         uint32_t i_left_pce  = 0;
963         uint32_t i_right_pce = 6;
964         uint32_t i_top_pce   = 2;
965         uint32_t i_btm_pce   = 4;
966 
967         uint32_t i_pce_pair = 0;
968         for (int32_t i_row = 0; i_row < p_sys->s_allocated.i_rows; i_row++)
969             for (int32_t i_col = 0; i_col < p_sys->s_allocated.i_cols; i_col++) {
970                 if (p_sys->ps_pieces[i_pce].i_original_row == p_sys->ps_pieces[i_pce_pair].i_original_row) {
971                     if (p_sys->ps_pieces[i_pce].i_original_col == p_sys->ps_pieces[i_pce_pair].i_original_col - 1)
972                         i_right_pce = i_pce_pair;
973                     else if (p_sys->ps_pieces[i_pce].i_original_col == p_sys->ps_pieces[i_pce_pair].i_original_col + 1)
974                         i_left_pce = i_pce_pair;
975                 }
976                 else if (p_sys->ps_pieces[i_pce].i_original_col == p_sys->ps_pieces[i_pce_pair].i_original_col) {
977                     if (p_sys->ps_pieces[i_pce].i_original_row == p_sys->ps_pieces[i_pce_pair].i_original_row - 1)
978                         i_btm_pce = i_pce_pair;
979                     else if (p_sys->ps_pieces[i_pce].i_original_row == p_sys->ps_pieces[i_pce_pair].i_original_row + 1)
980                         i_top_pce = i_pce_pair;
981                 }
982                 i_pce_pair++;
983             }
984 
985         if ((p_sys->ps_pieces[i_pce].i_left_shape == 0) && (p_sys->ps_pieces[i_pce].i_original_col != 0)) {
986             p_sys->ps_pieces[i_left_pce].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
987             p_sys->ps_pieces[i_pce].i_left_shape = (p_sys->ps_pieces[i_left_pce].i_right_shape - 6 ) ^ 0x01;
988         }
989 
990         if ((p_sys->ps_pieces[i_pce].i_right_shape == 6) && (p_sys->ps_pieces[i_pce].i_original_col != p_sys->s_allocated.i_cols-1)) {
991             p_sys->ps_pieces[i_pce].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
992             p_sys->ps_pieces[i_right_pce].i_left_shape = (p_sys->ps_pieces[i_pce].i_right_shape - 6 ) ^ 0x01;
993         }
994 
995         if ((p_sys->ps_pieces[i_pce].i_top_shape == 2) && (p_sys->ps_pieces[i_pce].i_original_row != 0)) {
996             p_sys->ps_pieces[i_top_pce].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
997             p_sys->ps_pieces[i_pce].i_top_shape = (p_sys->ps_pieces[i_top_pce].i_btm_shape - 2 ) ^ 0x01;
998         }
999 
1000         if ((p_sys->ps_pieces[i_pce].i_btm_shape == 4) && (p_sys->ps_pieces[i_pce].i_original_row != p_sys->s_allocated.i_rows-1)) {
1001             p_sys->ps_pieces[i_pce].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
1002             p_sys->ps_pieces[i_btm_pce].i_top_shape = (p_sys->ps_pieces[i_pce].i_btm_shape - 2 ) ^ 0x01;
1003         }
1004 
1005     }
1006 }
1007