Vout: move the AndroidSurface vout to a subdirectory
[vlc.git] / modules / video_filter / puzzle_mgt.c
blob8f2fd1907a2bb823991dbd48b7d5ccc371891475
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$
8 * Authors: Antoine Cellerier <dionoea -at- videolan -dot- org>
9 * Vianney Boyer <vlcvboyer -at- gmail -dot- com>
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.
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.
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 *****************************************************************************/
26 /*****************************************************************************
27 * Preamble
28 *****************************************************************************/
30 #ifdef HAVE_CONFIG_H
31 # include "config.h"
32 #endif
33 #include <math.h>
35 #include <vlc_common.h>
36 #include <vlc_plugin.h>
37 #include <vlc_filter.h>
38 #include <vlc_rand.h>
40 #include "filter_picture.h"
42 #include "puzzle_bezier.h"
43 #include "puzzle_lib.h"
44 #include "puzzle_pce.h"
45 #include "puzzle_mgt.h"
47 /*****************************************************************************
48 * puzzle_bake: compute general puzzle data and allocate structures
49 *****************************************************************************/
50 int puzzle_bake( filter_t *p_filter, picture_t *p_pic_out, picture_t *p_pic_in)
52 filter_sys_t *p_sys = p_filter->p_sys;
53 int i_ret = 0;
55 puzzle_free_ps_puzzle_array ( p_filter );
56 puzzle_free_ps_pieces_shapes ( p_filter);
57 puzzle_free_ps_pieces ( p_filter );
59 p_sys->s_allocated.i_rows = p_sys->s_current_param.i_rows;
60 p_sys->s_allocated.i_cols = p_sys->s_current_param.i_cols;
61 p_sys->s_allocated.i_planes = p_sys->s_current_param.i_planes;
62 p_sys->s_allocated.i_piece_types = ((p_sys->s_current_param.b_advanced)?PIECE_TYPE_NBR:0);
63 p_sys->s_allocated.i_pieces_nbr = p_sys->s_allocated.i_rows * p_sys->s_allocated.i_cols;
64 p_sys->s_allocated.b_preview = p_sys->s_current_param.b_preview;
65 p_sys->s_allocated.i_preview_size = p_sys->s_current_param.i_preview_size;
66 p_sys->s_allocated.i_border = p_sys->s_current_param.i_border;
67 p_sys->s_allocated.b_blackslot = p_sys->s_current_param.b_blackslot;
68 p_sys->s_allocated.b_near = p_sys->s_current_param.b_near;
69 p_sys->s_allocated.i_shape_size = p_sys->s_current_param.i_shape_size;
70 p_sys->s_allocated.b_advanced = p_sys->s_current_param.b_advanced;
71 p_sys->s_allocated.i_auto_shuffle_speed = p_sys->s_current_param.i_auto_shuffle_speed;
72 p_sys->s_allocated.i_auto_solve_speed = p_sys->s_current_param.i_auto_solve_speed;
73 p_sys->s_allocated.i_rotate = p_sys->s_current_param.i_rotate;
75 p_sys->ps_puzzle_array = malloc( sizeof( puzzle_array_t** ) * (p_sys->s_allocated.i_rows + 1));
76 if( !p_sys->ps_puzzle_array )
77 return VLC_ENOMEM;
79 for (int32_t r=0; r < p_sys->s_allocated.i_rows + 1; r++) {
80 p_sys->ps_puzzle_array[r] = malloc( sizeof( puzzle_array_t* ) * (p_sys->s_allocated.i_cols + 1));
81 if( !p_sys->ps_puzzle_array[r] )
82 return VLC_ENOMEM;
83 for (int32_t c=0; c < p_sys->s_allocated.i_cols + 1; c++) {
84 p_sys->ps_puzzle_array[r][c] = malloc( sizeof( puzzle_array_t ) * p_sys->s_allocated.i_planes);
85 if( !p_sys->ps_puzzle_array[r][c] )
86 return VLC_ENOMEM;
90 p_sys->ps_desk_planes = malloc( sizeof( puzzle_plane_t ) * p_sys->s_allocated.i_planes);
91 if( !p_sys->ps_desk_planes )
92 return VLC_ENOMEM;
93 p_sys->ps_pict_planes = malloc( sizeof( puzzle_plane_t ) * p_sys->s_allocated.i_planes);
94 if( !p_sys->ps_pict_planes )
95 return VLC_ENOMEM;
97 for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) {
98 p_sys->ps_desk_planes[i_plane].i_lines = p_pic_out->p[i_plane].i_visible_lines;
99 p_sys->ps_desk_planes[i_plane].i_pitch = p_pic_out->p[i_plane].i_pitch;
100 p_sys->ps_desk_planes[i_plane].i_visible_pitch = p_pic_out->p[i_plane].i_visible_pitch;
101 p_sys->ps_desk_planes[i_plane].i_pixel_pitch = p_pic_out->p[i_plane].i_pixel_pitch;
102 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 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;
105 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 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;
108 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 p_sys->ps_desk_planes[i_plane].i_pce_max_width = (( p_sys->ps_desk_planes[i_plane].i_width
111 - 2 * p_sys->ps_desk_planes[i_plane].i_border_width ) + p_sys->s_allocated.i_cols - 1 ) / p_sys->s_allocated.i_cols;
112 p_sys->ps_desk_planes[i_plane].i_pce_max_lines = (( p_sys->ps_desk_planes[i_plane].i_lines
113 - 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 p_sys->ps_pict_planes[i_plane].i_lines = p_pic_in->p[i_plane].i_visible_lines;
116 p_sys->ps_pict_planes[i_plane].i_pitch = p_pic_in->p[i_plane].i_pitch;
117 p_sys->ps_pict_planes[i_plane].i_visible_pitch = p_pic_in->p[i_plane].i_visible_pitch;
118 p_sys->ps_pict_planes[i_plane].i_pixel_pitch = p_pic_in->p[i_plane].i_pixel_pitch;
119 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 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;
122 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 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;
125 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 p_sys->ps_pict_planes[i_plane].i_pce_max_width = (( p_sys->ps_desk_planes[i_plane].i_width
128 - 2 * p_sys->ps_pict_planes[i_plane].i_border_width ) + p_sys->s_allocated.i_cols - 1 ) / p_sys->s_allocated.i_cols;
129 p_sys->ps_pict_planes[i_plane].i_pce_max_lines = (( p_sys->ps_pict_planes[i_plane].i_lines
130 - 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 for (int32_t r = 0; r < p_sys->s_allocated.i_rows; r++)
133 for (int32_t c = 0; c < p_sys->s_allocated.i_cols; c++) {
134 if ( r == 0 )
135 p_sys->ps_puzzle_array[r][c][i_plane].i_y = p_sys->ps_pict_planes[i_plane].i_border_lines;
136 if ( c == 0 )
137 p_sys->ps_puzzle_array[r][c][i_plane].i_x = p_sys->ps_pict_planes[i_plane].i_border_width;
138 p_sys->ps_puzzle_array[r][c][i_plane].i_width =
139 (p_sys->ps_pict_planes[i_plane].i_width - p_sys->ps_pict_planes[i_plane].i_border_width
140 - p_sys->ps_puzzle_array[r][c][i_plane].i_x) / ( p_sys->s_allocated.i_cols - c );
141 p_sys->ps_puzzle_array[r][c][i_plane].i_lines =
142 (p_sys->ps_pict_planes[i_plane].i_lines - p_sys->ps_pict_planes[i_plane].i_border_lines
143 - p_sys->ps_puzzle_array[r][c][i_plane].i_y) / ( p_sys->s_allocated.i_rows - r );
144 p_sys->ps_puzzle_array[r][c + 1][i_plane].i_x =
145 p_sys->ps_puzzle_array[r][c][i_plane].i_x + p_sys->ps_puzzle_array[r][c][i_plane].i_width;
146 p_sys->ps_puzzle_array[r + 1][c][i_plane].i_y =
147 p_sys->ps_puzzle_array[r][c][i_plane].i_y + p_sys->ps_puzzle_array[r][c][i_plane].i_lines;
151 p_sys->i_magnet_accuracy = ( p_sys->s_current_param.i_pict_width / 50) + 3;
153 if (p_sys->s_current_param.b_advanced && p_sys->s_allocated.i_shape_size != 0) {
154 i_ret = puzzle_bake_pieces_shapes ( p_filter );
155 if (i_ret != VLC_SUCCESS)
156 return i_ret;
159 i_ret = puzzle_bake_piece ( p_filter );
160 if (i_ret != VLC_SUCCESS)
161 return i_ret;
163 if ( (p_sys->pi_order != NULL) && (p_sys->ps_desk_planes != NULL) && (p_sys->ps_pict_planes != NULL)
164 && (p_sys->ps_puzzle_array != NULL) && (p_sys->ps_pieces != NULL) )
165 p_sys->b_init = true;
167 if ( (p_sys->ps_pieces_shapes == NULL) && (p_sys->s_current_param.b_advanced)
168 && (p_sys->s_current_param.i_shape_size != 0) )
169 p_sys->b_init = false;
171 return VLC_SUCCESS;
174 void puzzle_free_ps_puzzle_array( filter_t *p_filter)
176 filter_sys_t *p_sys = p_filter->p_sys;
178 if (p_sys->ps_puzzle_array != NULL) {
179 for (int32_t r=0; r < p_sys->s_allocated.i_rows + 1; r++) {
180 for (int32_t c=0; c < p_sys->s_allocated.i_cols + 1; c++)
181 free( p_sys->ps_puzzle_array[r][c] );
182 free( p_sys->ps_puzzle_array[r] );
184 free( p_sys->ps_puzzle_array );
186 p_sys->ps_puzzle_array = NULL;
188 free ( p_sys->ps_desk_planes );
189 p_sys->ps_desk_planes = NULL;
191 free ( p_sys->ps_pict_planes );
192 p_sys->ps_pict_planes = NULL;
194 return;
197 /*****************************************************************************
198 * puzzle_bake_piece: compute data dedicated to each piece
199 *****************************************************************************/
200 int puzzle_bake_piece( filter_t *p_filter)
202 int i_ret = puzzle_allocate_ps_pieces( p_filter);
203 if (i_ret != VLC_SUCCESS)
204 return i_ret;
206 filter_sys_t *p_sys = p_filter->p_sys;
208 /* generates random pi_order array */
209 i_ret = puzzle_shuffle( p_filter );
210 if (i_ret != VLC_SUCCESS)
211 return i_ret;
213 int32_t i = 0;
214 for (int32_t row = 0; row < p_sys->s_allocated.i_rows; row++) {
215 for (int32_t col = 0; col < p_sys->s_allocated.i_cols; col++) {
216 int32_t orow = row;
217 int32_t ocol = col;
219 if (p_sys->pi_order != NULL) {
220 orow = p_sys->pi_order[i] / (p_sys->s_allocated.i_cols);
221 ocol = p_sys->pi_order[i] % (p_sys->s_allocated.i_cols);
224 p_sys->ps_pieces[i].i_original_row = orow;
225 p_sys->ps_pieces[i].i_original_col = ocol;
227 /* set bottom and right shapes */
228 p_sys->ps_pieces[i].i_left_shape = 0;
229 p_sys->ps_pieces[i].i_top_shape = 2;
230 p_sys->ps_pieces[i].i_btm_shape = 4;
231 p_sys->ps_pieces[i].i_right_shape = 6;
233 if (p_sys->s_allocated.i_shape_size > 0) {
235 if (orow < p_sys->s_allocated.i_rows - 1)
236 p_sys->ps_pieces[i].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
238 if (ocol < p_sys->s_allocated.i_cols - 1)
239 p_sys->ps_pieces[i].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
242 /* set piece data */
243 p_sys->ps_pieces[i].i_actual_angle = 0;
244 p_sys->ps_pieces[i].b_overlap = false;
245 p_sys->ps_pieces[i].i_actual_mirror = +1;
246 p_sys->ps_pieces[i].b_finished = ((ocol == col) && (orow == row));
247 p_sys->ps_pieces[i].i_group_ID = i;
249 /* add small random offset to location */
250 int32_t i_rand_x = 0;
251 int32_t i_rand_y = 0;
252 if (p_sys->s_current_param.b_advanced) {
253 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;
254 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;
257 /* copy related puzzle data to piece data */
258 if (p_sys->ps_puzzle_array != NULL) {
259 for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) {
261 p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_width = p_sys->ps_puzzle_array[row][col][i_plane].i_width;
262 p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_lines = p_sys->ps_puzzle_array[row][col][i_plane].i_lines;
263 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;
264 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;
265 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 *
266 p_sys->ps_desk_planes[i_plane].i_width / p_sys->ps_desk_planes[0].i_width;
267 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 *
268 p_sys->ps_desk_planes[i_plane].i_lines / p_sys->ps_desk_planes[0].i_lines;
270 if (i_plane == 0) {
272 p_sys->ps_pieces[i].i_OLx = p_sys->ps_pieces[i].ps_piece_in_plane[0].i_original_x;
273 p_sys->ps_pieces[i].i_OTy = p_sys->ps_pieces[i].ps_piece_in_plane[0].i_original_y;
274 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;
275 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 puzzle_calculate_corners( p_filter, i );
281 i++;
285 /* left and top shapes are based on negative right and bottom ones */
286 puzzle_set_left_top_shapes( p_filter);
288 /* add random rotation to each piece */
289 puzzle_random_rotate( p_filter);
291 return VLC_SUCCESS;
294 /*****************************************************************************
295 * puzzle_set_left_top_shapes: Set the shape ID to be used for top and left
296 * edges of each piece. Those ID will be set to
297 * be the negative of bottom or right of adjacent
298 * piece.
299 *****************************************************************************/
300 void puzzle_set_left_top_shapes( filter_t *p_filter)
302 filter_sys_t *p_sys = p_filter->p_sys;
303 /* for each piece on the desk... */
304 for (uint16_t i_pce_B=0; i_pce_B < p_sys->s_allocated.i_pieces_nbr; i_pce_B++)
305 /* ...search adjacent piece */
306 for (uint16_t i_pce_A=0; i_pce_A < p_sys->s_allocated.i_pieces_nbr; i_pce_A++)
308 if ( ( p_sys->ps_pieces[i_pce_A].i_original_row == p_sys->ps_pieces[i_pce_B].i_original_row )
309 && ( p_sys->ps_pieces[i_pce_A].i_original_col == p_sys->ps_pieces[i_pce_B].i_original_col-1 ) )
310 /* left shape is based on negative (invert ID LSB) right one */
311 p_sys->ps_pieces[i_pce_B].i_left_shape = (p_sys->ps_pieces[i_pce_A].i_right_shape - 6 ) ^ 0x01;
313 if ( ( p_sys->ps_pieces[i_pce_A].i_original_row == p_sys->ps_pieces[i_pce_B].i_original_row - 1 )
314 && ( p_sys->ps_pieces[i_pce_A].i_original_col == p_sys->ps_pieces[i_pce_B].i_original_col ) )
315 /* top shape is based on negative of bottom one
316 * top ID = bottom ID - 2
317 * negative ID = invert LSB
319 p_sys->ps_pieces[i_pce_B].i_top_shape = (p_sys->ps_pieces[i_pce_A].i_btm_shape - 2 ) ^ 0x01;
323 void puzzle_random_rotate( filter_t *p_filter)
325 filter_sys_t *p_sys = p_filter->p_sys;
326 /* add random rotation to each piece */
327 for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++)
329 p_sys->ps_pieces[i].i_actual_angle = 0;
330 p_sys->ps_pieces[i].i_actual_mirror = +1;
332 switch ( p_sys->s_current_param.i_rotate )
334 case 1:
335 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 );
336 break;
337 case 2:
338 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 );
339 break;
340 case 3:
341 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 );
342 break;
344 puzzle_calculate_corners( p_filter, i );
348 void puzzle_free_ps_pieces( filter_t *p_filter)
350 filter_sys_t *p_sys = p_filter->p_sys;
352 if (p_sys->ps_pieces != NULL) {
353 for (uint32_t i_pce = 0; i_pce < p_sys->s_allocated.i_pieces_nbr; i_pce++)
354 free( p_sys->ps_pieces[i_pce].ps_piece_in_plane );
355 free( p_sys->ps_pieces );
357 p_sys->ps_pieces = NULL;
359 free( p_sys->pi_order );
360 p_sys->pi_order = NULL;
362 free( p_sys->ps_pieces_tmp );
363 p_sys->ps_pieces_tmp = NULL;
365 free( p_sys->pi_group_qty );
366 p_sys->pi_group_qty = NULL;
368 return;
371 int puzzle_allocate_ps_pieces( filter_t *p_filter)
373 filter_sys_t *p_sys = p_filter->p_sys;
374 puzzle_free_ps_pieces(p_filter);
375 p_sys->s_allocated.i_pieces_nbr = p_sys->s_allocated.i_rows * p_sys->s_allocated.i_cols;
376 p_sys->ps_pieces = malloc( sizeof( piece_t) * p_sys->s_allocated.i_pieces_nbr );
377 if( !p_sys->ps_pieces )
378 return VLC_ENOMEM;
379 for (uint32_t p = 0; p < p_sys->s_allocated.i_pieces_nbr; p++) {
380 p_sys->ps_pieces[p].ps_piece_in_plane = malloc( sizeof( piece_in_plane_t) * p_sys->s_allocated.i_planes );
381 if( !p_sys->ps_pieces[p].ps_piece_in_plane ) {
382 for (uint32_t i=0;i<p;i++)
383 free(p_sys->ps_pieces[i].ps_piece_in_plane);
384 free(p_sys->ps_pieces);
385 p_sys->ps_pieces = NULL;
386 return VLC_ENOMEM;
390 p_sys->ps_pieces_tmp = malloc( sizeof( piece_t) * p_sys->s_allocated.i_pieces_nbr );
391 if( !p_sys->ps_pieces_tmp ) {
392 for (uint32_t i=0;i<p_sys->s_allocated.i_pieces_nbr;i++)
393 free(p_sys->ps_pieces[i].ps_piece_in_plane);
394 free(p_sys->ps_pieces);
395 p_sys->ps_pieces = NULL;
396 return VLC_ENOMEM;
398 p_sys->pi_group_qty = malloc( sizeof( int32_t ) * (p_sys->s_allocated.i_pieces_nbr));
399 if( !p_sys->pi_group_qty ) {
400 for (uint32_t i=0;i<p_sys->s_allocated.i_pieces_nbr;i++)
401 free(p_sys->ps_pieces[i].ps_piece_in_plane);
402 free(p_sys->ps_pieces);
403 p_sys->ps_pieces = NULL;
404 free(p_sys->ps_pieces_tmp);
405 p_sys->ps_pieces_tmp = NULL;
406 return VLC_ENOMEM;
408 return VLC_SUCCESS;
411 bool puzzle_is_valid( filter_sys_t *p_sys, int32_t *pi_pce_lst )
413 const int32_t i_count = p_sys->s_allocated.i_pieces_nbr;
415 if( !p_sys->s_current_param.b_blackslot )
416 return true;
418 int32_t d = 0;
419 for( int32_t i = 0; i < i_count; i++ ) {
420 if( pi_pce_lst[i] == i_count - 1 ) {
421 d += i / p_sys->s_allocated.i_cols + 1;
422 continue;
424 for( int32_t j = i+1; j < i_count; j++ ) {
425 if( pi_pce_lst[j] == i_count - 1 )
426 continue;
427 if( pi_pce_lst[i] > pi_pce_lst[j] )
428 d++;
431 return (d%2) == 0;
434 int puzzle_shuffle( filter_t *p_filter )
436 filter_sys_t *p_sys = p_filter->p_sys;
438 int32_t i_pieces_nbr = p_sys->s_allocated.i_pieces_nbr;
442 int i_ret = puzzle_generate_rand_pce_list( p_filter, &p_sys->pi_order );
443 if (i_ret != VLC_SUCCESS)
444 return i_ret;
445 } while( puzzle_is_finished( p_sys, p_sys->pi_order ) || !puzzle_is_valid( p_sys, p_sys->pi_order ) );
448 if( p_sys->s_current_param.b_blackslot ) {
449 for( int32_t i = 0; i < i_pieces_nbr; i++ )
450 if( p_sys->pi_order[i] == i_pieces_nbr - 1 ) {
451 p_sys->i_selected = i;
452 break;
455 else {
456 p_sys->i_selected = NO_PCE;
459 p_sys->b_shuffle_rqst = false;
460 p_sys->b_finished = false;
462 return VLC_SUCCESS;
465 int puzzle_generate_rand_pce_list( filter_t *p_filter, int32_t **pi_pce_lst )
467 filter_sys_t *p_sys = p_filter->p_sys;
469 int32_t i_pieces_nbr = p_sys->s_allocated.i_pieces_nbr;
471 if (pi_pce_lst != NULL )
472 free( *pi_pce_lst );
473 *pi_pce_lst = calloc( i_pieces_nbr, sizeof(**pi_pce_lst) );
474 if( !*pi_pce_lst )
475 return VLC_ENOMEM;
477 for( int32_t i = 0; i < i_pieces_nbr; i++ )
478 (*pi_pce_lst)[i] = NO_PCE;
480 for( int32_t c = 0; c < i_pieces_nbr; ) {
481 int32_t i = ((unsigned)vlc_mrand48()) % i_pieces_nbr;
482 if( (*pi_pce_lst)[i] == NO_PCE )
483 (*pi_pce_lst)[i] = c++;
485 return VLC_SUCCESS;
488 bool puzzle_is_finished( filter_sys_t *p_sys, int32_t *pi_pce_lst )
490 for( uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++ )
491 if( (int32_t)i != pi_pce_lst[i] )
492 return false;
494 return true;
497 int puzzle_piece_foreground( filter_t *p_filter, int32_t i_piece) {
498 filter_sys_t *p_sys = p_filter->p_sys;
499 piece_t *ps_pieces_tmp; /* list [piece] of pieces data. Sort as per layers */
500 uint32_t i_group_ID = p_sys->ps_pieces[i_piece].i_group_ID;
502 ps_pieces_tmp = malloc( sizeof( piece_t) * p_sys->s_allocated.i_pieces_nbr );
503 if (!ps_pieces_tmp)
504 return VLC_ENOMEM;
506 int32_t j=0;
508 memcpy( &ps_pieces_tmp[j], &p_sys->ps_pieces[i_piece], sizeof(piece_t) );
509 j++;
511 for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
512 if ( ( p_sys->ps_pieces[i].i_group_ID == i_group_ID ) && ( (int32_t)i != i_piece ) ) {
513 memcpy( &ps_pieces_tmp[j], &p_sys->ps_pieces[i], sizeof(piece_t));
514 j++;
517 for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
518 if ( p_sys->ps_pieces[i].i_group_ID != i_group_ID ) {
519 memcpy( &ps_pieces_tmp[j], &p_sys->ps_pieces[i], sizeof(piece_t));
520 j++;
524 free( p_filter->p_sys->ps_pieces );
525 p_filter->p_sys->ps_pieces = ps_pieces_tmp;
527 return VLC_SUCCESS;
530 void puzzle_count_pce_group( filter_t *p_filter) { /* count pce in each group */
531 filter_sys_t *p_sys = p_filter->p_sys;
533 memset ( p_sys->pi_group_qty, 0, sizeof( int32_t ) * (p_sys->s_allocated.i_pieces_nbr) );
534 for (uint32_t i_pce = 0; i_pce < p_sys->s_allocated.i_pieces_nbr; i_pce++)
535 p_sys->pi_group_qty[p_sys->ps_pieces[i_pce].i_group_ID]++;
538 /*****************************************************************************
539 * puzzle_solve_pces_group: check if pieces are close together
540 * and then combine in a group
541 *****************************************************************************/
542 void puzzle_solve_pces_group( filter_t *p_filter) {
543 filter_sys_t *p_sys = p_filter->p_sys;
544 int32_t i_dx, i_dy;
546 p_sys->i_solve_grp_loop++;
547 p_sys->i_solve_grp_loop %= p_sys->s_allocated.i_pieces_nbr;
549 int32_t i_piece_A = p_sys->i_solve_grp_loop;
550 piece_t *ps_piece_A = &p_sys->ps_pieces[i_piece_A];
552 for (uint32_t i_piece_B = 0; i_piece_B < p_sys->s_allocated.i_pieces_nbr; i_piece_B++)
554 piece_t *ps_piece_B = &p_sys->ps_pieces[i_piece_B];
556 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 )
557 continue;
559 if ( (ps_piece_B->i_group_ID != p_sys->ps_pieces[i_piece_A].i_group_ID ) )
561 if ( abs(ps_piece_A->i_OTy - ps_piece_B->i_OTy )<3)
563 if ( abs( ps_piece_A->i_ORx - ps_piece_B->i_OLx + 1 ) < 3
564 && abs( ps_piece_A->i_TRx - ps_piece_B->i_TLx + 1 ) < p_sys->i_magnet_accuracy
565 && abs( ps_piece_A->i_TRy - ps_piece_B->i_TLy ) < p_sys->i_magnet_accuracy
566 && abs( ps_piece_A->i_BRx - ps_piece_B->i_BLx + 1 ) < p_sys->i_magnet_accuracy
567 && abs( ps_piece_A->i_BRy - ps_piece_B->i_BLy ) < p_sys->i_magnet_accuracy )
569 i_dx = ps_piece_A->i_TRx - ps_piece_B->i_TLx + ps_piece_A->i_step_x_x;
570 i_dy = ps_piece_A->i_TRy - ps_piece_B->i_TLy;
572 if (!ps_piece_B->b_finished)
573 puzzle_move_group( p_filter, i_piece_B, i_dx, i_dy);
574 else
575 puzzle_move_group( p_filter, i_piece_A, -i_dx, -i_dy);
577 uint32_t i_group_ID = ps_piece_B->i_group_ID;
578 for (uint32_t i_for = 0; i_for < p_sys->s_allocated.i_pieces_nbr; i_for++)
579 if ( p_sys->ps_pieces[i_for].i_group_ID == i_group_ID)
580 p_sys->ps_pieces[i_for].i_group_ID = p_sys->ps_pieces[i_piece_A].i_group_ID;
583 else if ( abs(ps_piece_A->i_OLx - ps_piece_B->i_OLx ) < 3 )
585 if ( abs(ps_piece_A->i_OBy - ps_piece_B->i_OTy + 1 ) < 3
586 && abs( ps_piece_B->i_TLx - ps_piece_A->i_BLx ) < p_sys->i_magnet_accuracy
587 && abs( ps_piece_B->i_TLy - 1 - ps_piece_A->i_BLy ) < p_sys->i_magnet_accuracy
588 && abs( ps_piece_B->i_TRx - ps_piece_A->i_BRx ) < p_sys->i_magnet_accuracy
589 && abs( ps_piece_B->i_TRy - 1 - ps_piece_A->i_BRy ) < p_sys->i_magnet_accuracy )
592 i_dx = ps_piece_A->i_BLx - ps_piece_B->i_TLx;
593 i_dy = ps_piece_A->i_BLy - ps_piece_B->i_TLy + ps_piece_A->i_step_y_y;
595 if (!ps_piece_B->b_finished)
596 puzzle_move_group( p_filter, i_piece_B, i_dx, i_dy);
597 else
598 puzzle_move_group( p_filter, i_piece_A, -i_dx, -i_dy);
600 uint32_t i_group_ID = ps_piece_B->i_group_ID;
601 for (uint32_t i_for = 0; i_for < p_sys->s_allocated.i_pieces_nbr; i_for++)
602 if ( p_sys->ps_pieces[i_for].i_group_ID == i_group_ID)
603 p_sys->ps_pieces[i_for].i_group_ID = p_sys->ps_pieces[i_piece_A].i_group_ID;
608 if ( abs( ps_piece_A->i_OTy - ps_piece_B->i_OTy ) < 3 )
610 if ( abs( ps_piece_A->i_ORx - ps_piece_B->i_OLx + 1 ) < 3
611 && abs( ps_piece_A->i_TRx - ps_piece_B->i_TLx + 1 ) < p_sys->i_magnet_accuracy
612 && abs( ps_piece_A->i_TRy - ps_piece_B->i_TLy ) < p_sys->i_magnet_accuracy
613 && abs( ps_piece_A->i_BRx - ps_piece_B->i_BLx + 1 ) < p_sys->i_magnet_accuracy
614 && abs( ps_piece_A->i_BRy - ps_piece_B->i_BLy ) < p_sys->i_magnet_accuracy )
616 ps_piece_B->i_left_shape = 0;
617 ps_piece_A->i_right_shape = 6;
620 else if ( abs( ps_piece_A->i_OLx - ps_piece_B->i_OLx )<3 )
622 if ( abs( ps_piece_A->i_OBy - ps_piece_B->i_OTy + 1 )<3
623 && abs( ps_piece_B->i_TLx - ps_piece_A->i_BLx ) < p_sys->i_magnet_accuracy
624 && abs( ps_piece_B->i_TLy - 1 - ps_piece_A->i_BLy ) < p_sys->i_magnet_accuracy
625 && abs( ps_piece_B->i_TRx - ps_piece_A->i_BRx ) < p_sys->i_magnet_accuracy
626 && abs( ps_piece_B->i_TRy - 1 - ps_piece_A->i_BRy ) < p_sys->i_magnet_accuracy )
628 ps_piece_B->i_top_shape = 2;
629 ps_piece_A->i_btm_shape = 4;
635 /*****************************************************************************
636 * puzzle_solve_pces_accuracy: check if pieces are close to their final location
637 * and then adjust position accordingly
638 *****************************************************************************/
639 void puzzle_solve_pces_accuracy( filter_t *p_filter) {
640 filter_sys_t *p_sys = p_filter->p_sys;
642 p_sys->i_solve_acc_loop++;
643 if (p_sys->i_solve_acc_loop >= p_sys->s_allocated.i_pieces_nbr) {
644 p_sys->i_done_count = p_sys->i_tmp_done_count;
645 p_sys->i_tmp_done_count = 0;
646 p_sys->i_solve_acc_loop = 0;
647 p_sys->b_finished = (p_sys->i_done_count == p_sys->s_allocated.i_pieces_nbr);
650 piece_t *ps_piece = &p_sys->ps_pieces[p_sys->i_solve_acc_loop];
652 ps_piece->b_finished = false;
653 if ( ps_piece->i_actual_mirror == 1
654 && abs( ps_piece->i_TRx - ps_piece->i_ORx ) < p_sys->i_magnet_accuracy
655 && abs( ps_piece->i_TRy - ps_piece->i_OTy ) < p_sys->i_magnet_accuracy
656 && abs( ps_piece->i_TLx - ps_piece->i_OLx ) < p_sys->i_magnet_accuracy
657 && abs( ps_piece->i_TLy - ps_piece->i_OTy ) < p_sys->i_magnet_accuracy )
659 uint32_t i_group_ID = ps_piece->i_group_ID;
660 p_sys->i_tmp_done_count++;
662 for ( uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
663 ps_piece = &p_sys->ps_pieces[i];
664 if ( ( ps_piece->i_group_ID == i_group_ID ) && ( !ps_piece->b_finished ) ) {
665 ps_piece->ps_piece_in_plane[0].i_actual_x = ps_piece->i_OLx;
666 ps_piece->ps_piece_in_plane[0].i_actual_y = ps_piece->i_OTy;
667 ps_piece->i_actual_mirror = +1;
668 puzzle_calculate_corners( p_filter, i );
669 ps_piece->b_finished = true;
675 /*****************************************************************************
676 * puzzle_sort_layers: sort pieces in order to see in foreground the
677 * standalone ones and those are at the wrong place
678 *****************************************************************************/
679 int puzzle_sort_layers( filter_t *p_filter)
681 filter_sys_t *p_sys = p_filter->p_sys;
683 int32_t i_idx = 0;
684 for (uint32_t i_qty = 1; i_qty <= p_sys->s_current_param.i_pieces_nbr; i_qty++) {
685 /* pieces at the wrong place are in foreground */
686 for (uint32_t i_pce_loop = 0; i_pce_loop < p_sys->s_current_param.i_pieces_nbr; i_pce_loop++) {
687 uint32_t i_grp = p_sys->ps_pieces[i_pce_loop].i_group_ID;
688 if ( p_sys->pi_group_qty[i_grp] == (int32_t)i_qty ) {
689 bool b_check_ok = true;
690 for (int32_t i_pce_check = 0; i_pce_check < i_idx; i_pce_check++)
691 if ( p_sys->ps_pieces_tmp[i_pce_check].i_group_ID == i_grp )
692 b_check_ok = false;
693 if ( b_check_ok )
694 for (uint32_t i_pce = i_pce_loop; i_pce < p_sys->s_current_param.i_pieces_nbr; i_pce++)
695 if (( p_sys->ps_pieces[i_pce].i_group_ID == i_grp ) && !p_sys->ps_pieces[i_pce].b_finished ) {
696 memcpy( &p_sys->ps_pieces_tmp[i_idx], &p_sys->ps_pieces[i_pce], sizeof(piece_t));
697 i_idx++;
701 /* pieces at the final location are in background */
702 for (uint32_t i_pce_loop = 0; i_pce_loop < p_sys->s_current_param.i_pieces_nbr; i_pce_loop++) {
703 uint32_t i_grp = p_sys->ps_pieces[i_pce_loop].i_group_ID;
704 if ( p_sys->pi_group_qty[i_grp] == (int32_t)i_qty ) {
705 bool b_check_ok = true;
706 for (int32_t i_pce_check = 0; i_pce_check < i_idx; i_pce_check++)
707 if ( p_sys->ps_pieces_tmp[i_pce_check].i_group_ID == i_grp && p_sys->ps_pieces_tmp[i_pce_check].b_finished )
708 b_check_ok = false;
709 if ( b_check_ok )
710 for (uint32_t i_pce = i_pce_loop; i_pce < p_sys->s_current_param.i_pieces_nbr; i_pce++)
711 if (( p_sys->ps_pieces[i_pce].i_group_ID == i_grp ) && p_sys->ps_pieces[i_pce].b_finished ) {
712 memcpy( &p_sys->ps_pieces_tmp[i_idx], &p_sys->ps_pieces[i_pce], sizeof(piece_t));
713 i_idx++;
719 free( p_filter->p_sys->ps_pieces );
720 p_filter->p_sys->ps_pieces = p_sys->ps_pieces_tmp;
721 p_sys->ps_pieces_tmp = malloc( sizeof( piece_t) * p_sys->s_allocated.i_pieces_nbr );
722 if (!p_sys->ps_pieces_tmp)
723 return VLC_ENOMEM;
725 return VLC_SUCCESS;
728 /*****************************************************************************
729 * puzzle_auto_solve: solve the puzzle depending on auto_solve_speed parameter
730 * = move one piece at the final location each time
731 * auto_solve_countdown is < 0
732 *****************************************************************************/
733 void puzzle_auto_solve( filter_t *p_filter)
735 filter_sys_t *p_sys = p_filter->p_sys;
737 if ( p_sys->s_current_param.i_auto_solve_speed < 500 )
738 return;
740 if ( --p_sys->i_auto_solve_countdown_val > 0 )
741 return;
743 /* delay reached, preset next delay and proceed with puzzle_auto_solve */
744 p_sys->i_auto_solve_countdown_val = init_countdown(p_sys->s_current_param.i_auto_solve_speed);
746 /* random piece to be moved */
747 int32_t i_start = ((unsigned)vlc_mrand48()) % p_sys->s_allocated.i_pieces_nbr;
749 /* here the computer will help player by placing the piece at the final location */
750 for (uint32_t i_l = 0; i_l < p_sys->s_allocated.i_pieces_nbr; i_l++) {
751 int32_t i = ( i_l + i_start ) % p_sys->s_allocated.i_pieces_nbr;
752 if ( !p_sys->ps_pieces[i].b_finished ) {
753 for (uint32_t j = 0; j < p_sys->s_allocated.i_pieces_nbr; j++) {
754 if ( p_sys->ps_pieces[j].i_group_ID == p_sys->ps_pieces[i].i_group_ID ) {
755 p_sys->ps_pieces[j].i_actual_angle = 0;
756 p_sys->ps_pieces[j].i_actual_mirror = +1;
757 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;
758 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;
759 puzzle_calculate_corners( p_filter, j );
762 break;
767 /*****************************************************************************
768 * puzzle_auto_shuffle: shuffle the pieces on the desk depending on
769 * auto_shuffle_speed parameter
770 * = random move of one piece each time
771 * auto_shuffle_countdown is < 0
772 *****************************************************************************/
773 void puzzle_auto_shuffle( filter_t *p_filter)
775 filter_sys_t *p_sys = p_filter->p_sys;
777 if ( p_sys->s_current_param.i_auto_shuffle_speed < 500 )
778 return;
780 if ( --p_sys->i_auto_shuffle_countdown_val > 0 )
781 return;
783 /* delay reached, preset next delay and proceed with puzzle_auto_shuffle */
784 p_sys->i_auto_shuffle_countdown_val = init_countdown(p_sys->s_current_param.i_auto_shuffle_speed);
786 /* random piece to be moved */
787 int32_t i_start = ((unsigned)vlc_mrand48()) % p_sys->s_allocated.i_pieces_nbr;
789 for (uint32_t i_l = 0; i_l < p_sys->s_allocated.i_pieces_nbr; i_l++){
790 int32_t i = ( i_l + i_start ) % p_sys->s_allocated.i_pieces_nbr;
792 /* find one piece which is part of one group */
793 if ( p_sys->pi_group_qty[p_sys->ps_pieces[i].i_group_ID] > 1 ) {
794 /* find an empty group to be used by this dismantled piece */
795 uint32_t i_new_group;
796 for ( i_new_group = 0 ; i_new_group < p_sys->s_allocated.i_pieces_nbr ; i_new_group ++ )
797 if ( p_sys->pi_group_qty[i_new_group] == 0 )
798 break;
799 p_sys->ps_pieces[i].i_group_ID = i_new_group;
800 p_sys->ps_pieces[i].b_finished = false;
802 /* random rotate & mirror */
803 switch ( p_sys->s_current_param.i_rotate )
805 case 1:
806 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 );
807 break;
808 case 2:
809 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 );
810 break;
811 case 3:
812 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 );
813 break;
816 /* random mvt */
817 p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_x =
818 p_sys->ps_desk_planes[0].i_border_width
819 + ( (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)
820 + p_sys->ps_pieces[i].ps_piece_in_plane[0].i_width / 2 * ( 1 - p_sys->ps_pieces[i].i_step_x_x )
821 - (p_sys->ps_pieces[i].ps_piece_in_plane[0].i_lines / 2) * p_sys->ps_pieces[i].i_step_y_x;
822 p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_y =
823 p_sys->ps_desk_planes[0].i_border_lines
824 + ( (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)
825 + p_sys->ps_pieces[i].ps_piece_in_plane[0].i_lines / 2 * ( 1 - p_sys->ps_pieces[i].i_step_y_y )
826 - (p_sys->ps_pieces[i].ps_piece_in_plane[0].i_width / 2) * p_sys->ps_pieces[i].i_step_x_y;
828 /* redefine shapes */
829 uint32_t i_left_pce = 0;
830 uint32_t i_right_pce = 6;
831 uint32_t i_top_pce = 2;
832 uint32_t i_btm_pce = 4;
834 uint32_t i_pce = 0;
835 for (int32_t i_row = 0; i_row < p_sys->s_allocated.i_rows; i_row++)
836 for (int32_t i_col = 0; i_col < p_sys->s_allocated.i_cols; i_col++) {
837 if (p_sys->ps_pieces[i].i_original_row == p_sys->ps_pieces[i_pce].i_original_row) {
838 if (p_sys->ps_pieces[i].i_original_col == p_sys->ps_pieces[i_pce].i_original_col - 1)
839 i_right_pce = i_pce;
840 else if (p_sys->ps_pieces[i].i_original_col == p_sys->ps_pieces[i_pce].i_original_col + 1)
841 i_left_pce = i_pce;
843 else if (p_sys->ps_pieces[i].i_original_col == p_sys->ps_pieces[i_pce].i_original_col) {
844 if (p_sys->ps_pieces[i].i_original_row == p_sys->ps_pieces[i_pce].i_original_row - 1)
845 i_btm_pce = i_pce;
846 else if (p_sys->ps_pieces[i].i_original_row == p_sys->ps_pieces[i_pce].i_original_row + 1)
847 i_top_pce = i_pce;
849 i_pce++;
852 if ((p_sys->ps_pieces[i].i_left_shape == 0) && (p_sys->ps_pieces[i].i_original_col != 0)) {
853 p_sys->ps_pieces[i_left_pce].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
854 p_sys->ps_pieces[i].i_left_shape = (p_sys->ps_pieces[i_left_pce].i_right_shape - 6 ) ^ 0x01;
857 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)) {
858 p_sys->ps_pieces[i].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
859 p_sys->ps_pieces[i_right_pce].i_left_shape = (p_sys->ps_pieces[i].i_right_shape - 6 ) ^ 0x01;
862 if ((p_sys->ps_pieces[i].i_top_shape == 2) && (p_sys->ps_pieces[i].i_original_row != 0)) {
863 p_sys->ps_pieces[i_top_pce].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
864 p_sys->ps_pieces[i].i_top_shape = (p_sys->ps_pieces[i_top_pce].i_btm_shape - 2 ) ^ 0x01;
867 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)) {
868 p_sys->ps_pieces[i].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
869 p_sys->ps_pieces[i_btm_pce].i_top_shape = (p_sys->ps_pieces[i].i_btm_shape - 2 ) ^ 0x01;
872 puzzle_calculate_corners( p_filter, i );
873 break;
878 /*****************************************************************************
879 * puzzle_save: save pieces location in memory
880 *****************************************************************************/
881 save_game_t* puzzle_save(filter_t *p_filter)
883 filter_sys_t *p_sys = p_filter->p_sys;
885 save_game_t *ps_save_game = calloc(1, sizeof(*ps_save_game));
886 if (!ps_save_game)
887 return NULL;
889 ps_save_game->i_cols = p_sys->s_allocated.i_cols;
890 ps_save_game->i_rows = p_sys->s_allocated.i_rows;
891 ps_save_game->i_rotate = p_sys->s_allocated.i_rotate;
893 ps_save_game->ps_pieces = calloc( ps_save_game->i_cols * ps_save_game->i_rows , sizeof(*ps_save_game->ps_pieces));
894 if (!ps_save_game->ps_pieces) {
895 free(ps_save_game);
896 return NULL;
899 int32_t i_border_width = p_sys->ps_desk_planes[0].i_border_width;
900 int32_t i_border_lines = p_sys->ps_desk_planes[0].i_border_lines;
902 for (int32_t i_pce = 0; i_pce < ps_save_game->i_cols * ps_save_game->i_rows; i_pce++) {
903 ps_save_game->ps_pieces[i_pce].i_original_row = p_sys->ps_pieces[i_pce].i_original_row;
904 ps_save_game->ps_pieces[i_pce].i_original_col = p_sys->ps_pieces[i_pce].i_original_col;
905 ps_save_game->ps_pieces[i_pce].i_top_shape = p_sys->ps_pieces[i_pce].i_top_shape;
906 ps_save_game->ps_pieces[i_pce].i_btm_shape = p_sys->ps_pieces[i_pce].i_btm_shape;
907 ps_save_game->ps_pieces[i_pce].i_right_shape = p_sys->ps_pieces[i_pce].i_right_shape;
908 ps_save_game->ps_pieces[i_pce].i_left_shape = p_sys->ps_pieces[i_pce].i_left_shape;
909 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);
910 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);
911 ps_save_game->ps_pieces[i_pce].i_actual_angle = p_sys->ps_pieces[i_pce].i_actual_angle;
912 ps_save_game->ps_pieces[i_pce].i_actual_mirror = p_sys->ps_pieces[i_pce].i_actual_mirror;
915 return ps_save_game;
918 void puzzle_load( filter_t *p_filter, save_game_t *ps_save_game)
920 filter_sys_t *p_sys = p_filter->p_sys;
922 if (p_sys->s_current_param.i_cols != ps_save_game->i_cols
923 || p_sys->s_allocated.i_rows != ps_save_game->i_rows
924 || p_sys->s_allocated.i_rotate != ps_save_game->i_rotate)
925 return;
927 int32_t i_border_width = p_sys->ps_desk_planes[0].i_border_width;
928 int32_t i_border_lines = p_sys->ps_desk_planes[0].i_border_lines;
930 for (uint32_t i_pce=0; i_pce < p_sys->s_allocated.i_pieces_nbr; i_pce++) {
931 for (uint32_t i=0; i < p_sys->s_allocated.i_pieces_nbr; i++)
932 if ( p_sys->ps_pieces[i].i_original_row == ps_save_game->ps_pieces[i_pce].i_original_row
933 && p_sys->ps_pieces[i].i_original_col == ps_save_game->ps_pieces[i_pce].i_original_col )
935 p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_x = i_border_width
936 + ((float)p_sys->ps_desk_planes[0].i_width - 2 * i_border_width)
937 * ps_save_game->ps_pieces[i_pce].f_pos_x;
938 p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_y = i_border_lines
939 + ((float)p_sys->ps_desk_planes[0].i_lines - 2 * i_border_lines)
940 * ps_save_game->ps_pieces[i_pce].f_pos_y;
942 p_sys->ps_pieces[i].i_top_shape = ps_save_game->ps_pieces[i_pce].i_top_shape;
943 p_sys->ps_pieces[i].i_btm_shape = ps_save_game->ps_pieces[i_pce].i_btm_shape;
944 p_sys->ps_pieces[i].i_right_shape = ps_save_game->ps_pieces[i_pce].i_right_shape;
945 p_sys->ps_pieces[i].i_left_shape = ps_save_game->ps_pieces[i_pce].i_left_shape;
946 p_sys->ps_pieces[i].i_actual_angle = ps_save_game->ps_pieces[i_pce].i_actual_angle;
947 p_sys->ps_pieces[i].i_actual_mirror = ps_save_game->ps_pieces[i_pce].i_actual_mirror;
948 p_sys->ps_pieces[i].i_group_ID = i_pce;
949 p_sys->ps_pieces[i].b_finished = false;
951 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
952 - 2*i_border_width) * ps_save_game->ps_pieces[i_pce].f_pos_x;
953 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
954 - 2*i_border_lines) * ps_save_game->ps_pieces[i_pce].f_pos_y;
955 puzzle_calculate_corners( p_filter, i );
957 break;
961 for (uint32_t i_pce=0; i_pce < p_sys->s_allocated.i_pieces_nbr; i_pce++) {
962 /* redefine shapes */
963 uint32_t i_left_pce = 0;
964 uint32_t i_right_pce = 6;
965 uint32_t i_top_pce = 2;
966 uint32_t i_btm_pce = 4;
968 uint32_t i_pce_pair = 0;
969 for (int32_t i_row = 0; i_row < p_sys->s_allocated.i_rows; i_row++)
970 for (int32_t i_col = 0; i_col < p_sys->s_allocated.i_cols; i_col++) {
971 if (p_sys->ps_pieces[i_pce].i_original_row == p_sys->ps_pieces[i_pce_pair].i_original_row) {
972 if (p_sys->ps_pieces[i_pce].i_original_col == p_sys->ps_pieces[i_pce_pair].i_original_col - 1)
973 i_right_pce = i_pce_pair;
974 else if (p_sys->ps_pieces[i_pce].i_original_col == p_sys->ps_pieces[i_pce_pair].i_original_col + 1)
975 i_left_pce = i_pce_pair;
977 else if (p_sys->ps_pieces[i_pce].i_original_col == p_sys->ps_pieces[i_pce_pair].i_original_col) {
978 if (p_sys->ps_pieces[i_pce].i_original_row == p_sys->ps_pieces[i_pce_pair].i_original_row - 1)
979 i_btm_pce = i_pce_pair;
980 else if (p_sys->ps_pieces[i_pce].i_original_row == p_sys->ps_pieces[i_pce_pair].i_original_row + 1)
981 i_top_pce = i_pce_pair;
983 i_pce_pair++;
986 if ((p_sys->ps_pieces[i_pce].i_left_shape == 0) && (p_sys->ps_pieces[i_pce].i_original_col != 0)) {
987 p_sys->ps_pieces[i_left_pce].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
988 p_sys->ps_pieces[i_pce].i_left_shape = (p_sys->ps_pieces[i_left_pce].i_right_shape - 6 ) ^ 0x01;
991 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)) {
992 p_sys->ps_pieces[i_pce].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
993 p_sys->ps_pieces[i_right_pce].i_left_shape = (p_sys->ps_pieces[i_pce].i_right_shape - 6 ) ^ 0x01;
996 if ((p_sys->ps_pieces[i_pce].i_top_shape == 2) && (p_sys->ps_pieces[i_pce].i_original_row != 0)) {
997 p_sys->ps_pieces[i_top_pce].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
998 p_sys->ps_pieces[i_pce].i_top_shape = (p_sys->ps_pieces[i_top_pce].i_btm_shape - 2 ) ^ 0x01;
1001 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)) {
1002 p_sys->ps_pieces[i_pce].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01);
1003 p_sys->ps_pieces[i_btm_pce].i_top_shape = (p_sys->ps_pieces[i_pce].i_btm_shape - 2 ) ^ 0x01;