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