/***************************************************************************** * puzzle_solve_pces_accuracy: check if pieces are close to their final location * and then adjust position accordingly *****************************************************************************/ void puzzle_solve_pces_accuracy( filter_t *p_filter) { filter_sys_t *p_sys = p_filter->p_sys; p_sys->i_solve_acc_loop++; if (p_sys->i_solve_acc_loop >= p_sys->s_allocated.i_pieces_nbr) { p_sys->i_done_count = p_sys->i_tmp_done_count; p_sys->i_tmp_done_count = 0; p_sys->i_solve_acc_loop = 0; p_sys->b_finished = (p_sys->i_done_count == p_sys->s_allocated.i_pieces_nbr); } piece_t *ps_piece = &p_sys->ps_pieces[p_sys->i_solve_acc_loop]; ps_piece->b_finished = false; if ( ps_piece->i_actual_mirror == 1 && abs( ps_piece->i_TRx - ps_piece->i_ORx ) < p_sys->i_magnet_accuracy && abs( ps_piece->i_TRy - ps_piece->i_OTy ) < p_sys->i_magnet_accuracy && abs( ps_piece->i_TLx - ps_piece->i_OLx ) < p_sys->i_magnet_accuracy && abs( ps_piece->i_TLy - ps_piece->i_OTy ) < p_sys->i_magnet_accuracy ) { uint32_t i_group_ID = ps_piece->i_group_ID; p_sys->i_tmp_done_count++; for ( uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) { ps_piece = &p_sys->ps_pieces[i]; if ( ( ps_piece->i_group_ID == i_group_ID ) && ( !ps_piece->b_finished ) ) { ps_piece->ps_piece_in_plane[0].i_actual_x = ps_piece->i_OLx; ps_piece->ps_piece_in_plane[0].i_actual_y = ps_piece->i_OTy; ps_piece->i_actual_mirror = +1; puzzle_calculate_corners( p_filter, i ); ps_piece->b_finished = true; } } } }
/***************************************************************************** * puzzle_auto_solve: solve the puzzle depending on auto_solve_speed parameter * = move one piece at the final location each time * auto_solve_countdown is < 0 *****************************************************************************/ void puzzle_auto_solve( filter_t *p_filter) { filter_sys_t *p_sys = p_filter->p_sys; if ( p_sys->s_current_param.i_auto_solve_speed < 500 ) return; if ( --p_sys->i_auto_solve_countdown_val > 0 ) return; /* delay reached, preset next delay and proceed with puzzle_auto_solve */ p_sys->i_auto_solve_countdown_val = init_countdown(p_sys->s_current_param.i_auto_solve_speed); /* random piece to be moved */ int32_t i_start = ((unsigned)vlc_mrand48()) % p_sys->s_allocated.i_pieces_nbr; /* here the computer will help player by placing the piece at the final location */ for (uint32_t i_l = 0; i_l < p_sys->s_allocated.i_pieces_nbr; i_l++) { int32_t i = ( i_l + i_start ) % p_sys->s_allocated.i_pieces_nbr; if ( !p_sys->ps_pieces[i].b_finished ) { for (uint32_t j = 0; j < p_sys->s_allocated.i_pieces_nbr; j++) { if ( p_sys->ps_pieces[j].i_group_ID == p_sys->ps_pieces[i].i_group_ID ) { p_sys->ps_pieces[j].i_actual_angle = 0; p_sys->ps_pieces[j].i_actual_mirror = +1; 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; 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; puzzle_calculate_corners( p_filter, j ); } } break; } } }
/***************************************************************************** * move group of joined pieces when user drag'n drop it with mouse *****************************************************************************/ void puzzle_move_group( filter_t *p_filter, int32_t i_piece, int32_t i_dx, int32_t i_dy) { filter_sys_t *p_sys = p_filter->p_sys; uint32_t i_group_ID = p_sys->ps_pieces[i_piece].i_group_ID; for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) { piece_t *ps_piece = &p_sys->ps_pieces[i]; if (ps_piece->i_group_ID == i_group_ID) { ps_piece->b_finished = false; ps_piece->ps_piece_in_plane[0].i_actual_x += i_dx; ps_piece->ps_piece_in_plane[0].i_actual_y += i_dy; puzzle_calculate_corners( p_filter, i ); } } }
void puzzle_load( filter_t *p_filter, save_game_t *ps_save_game) { filter_sys_t *p_sys = p_filter->p_sys; if (p_sys->s_current_param.i_cols != ps_save_game->i_cols || p_sys->s_allocated.i_rows != ps_save_game->i_rows || p_sys->s_allocated.i_rotate != ps_save_game->i_rotate) return; int32_t i_border_width = p_sys->ps_desk_planes[0].i_border_width; int32_t i_border_lines = p_sys->ps_desk_planes[0].i_border_lines; for (uint32_t i_pce=0; i_pce < p_sys->s_allocated.i_pieces_nbr; i_pce++) { for (uint32_t i=0; i < p_sys->s_allocated.i_pieces_nbr; i++) if ( p_sys->ps_pieces[i].i_original_row == ps_save_game->ps_pieces[i_pce].i_original_row && p_sys->ps_pieces[i].i_original_col == ps_save_game->ps_pieces[i_pce].i_original_col ) { 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 - 2 * i_border_width) * ps_save_game->ps_pieces[i_pce].f_pos_x; 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 - 2 * i_border_lines) * ps_save_game->ps_pieces[i_pce].f_pos_y; p_sys->ps_pieces[i].i_top_shape = ps_save_game->ps_pieces[i_pce].i_top_shape; p_sys->ps_pieces[i].i_btm_shape = ps_save_game->ps_pieces[i_pce].i_btm_shape; p_sys->ps_pieces[i].i_right_shape = ps_save_game->ps_pieces[i_pce].i_right_shape; p_sys->ps_pieces[i].i_left_shape = ps_save_game->ps_pieces[i_pce].i_left_shape; p_sys->ps_pieces[i].i_actual_angle = ps_save_game->ps_pieces[i_pce].i_actual_angle; p_sys->ps_pieces[i].i_actual_mirror = ps_save_game->ps_pieces[i_pce].i_actual_mirror; p_sys->ps_pieces[i].i_group_ID = i_pce; p_sys->ps_pieces[i].b_finished = false; 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 - 2*i_border_width) * ps_save_game->ps_pieces[i_pce].f_pos_x; 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 - 2*i_border_lines) * ps_save_game->ps_pieces[i_pce].f_pos_y; puzzle_calculate_corners( p_filter, i ); break; } } }
/***************************************************************************** * rotate piece when user click on mouse *****************************************************************************/ void puzzle_rotate_pce( filter_t *p_filter, int32_t i_piece, int8_t i_rotate_mirror, int32_t i_center_x, int32_t i_center_y, bool b_avoid_mirror ) { filter_sys_t *p_sys = p_filter->p_sys; piece_t *ps_piece = &p_sys->ps_pieces[i_piece]; if ( p_sys->s_current_param.i_rotate == 0 ) return; if ( p_sys->s_current_param.i_rotate == 1 && (i_rotate_mirror != 2) ) return; for ( uint8_t i=0; i < abs( i_rotate_mirror ); i++) { int32_t i_tempx, i_tempy; /* piece has to be rotated by 90° */ if ( i_rotate_mirror > 0 ) { ps_piece->i_actual_angle++; ps_piece->i_actual_angle &= 0x03; i_tempx = -( i_center_y - ps_piece->ps_piece_in_plane[0].i_actual_y ) + i_center_x; i_tempy = +( i_center_x - ps_piece->ps_piece_in_plane[0].i_actual_x ) + i_center_y; } else { ps_piece->i_actual_angle--; ps_piece->i_actual_angle &= 0x03; i_tempx = +( i_center_y - ps_piece->ps_piece_in_plane[0].i_actual_y ) + i_center_x; i_tempy = -( i_center_x - ps_piece->ps_piece_in_plane[0].i_actual_x ) + i_center_y; } ps_piece->ps_piece_in_plane[0].i_actual_x = i_tempx; ps_piece->ps_piece_in_plane[0].i_actual_y = i_tempy; if ( ps_piece->i_actual_angle == 0 && p_sys->s_current_param.i_rotate == 3 && !b_avoid_mirror ) { ps_piece->ps_piece_in_plane[0].i_actual_x = 2 * i_center_x - ps_piece->ps_piece_in_plane[0].i_actual_x; ps_piece->i_actual_mirror *= -1; } puzzle_calculate_corners( p_filter, i_piece ); } }
void puzzle_random_rotate( filter_t *p_filter) { filter_sys_t *p_sys = p_filter->p_sys; /* add random rotation to each piece */ for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) { p_sys->ps_pieces[i].i_actual_angle = 0; p_sys->ps_pieces[i].i_actual_mirror = +1; switch ( p_sys->s_current_param.i_rotate ) { case 1: 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 ); break; case 2: 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 ); break; case 3: 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 ); break; } puzzle_calculate_corners( p_filter, i ); } }
/***************************************************************************** * puzzle_auto_shuffle: shuffle the pieces on the desk depending on * auto_shuffle_speed parameter * = random move of one piece each time * auto_shuffle_countdown is < 0 *****************************************************************************/ void puzzle_auto_shuffle( filter_t *p_filter) { filter_sys_t *p_sys = p_filter->p_sys; if ( p_sys->s_current_param.i_auto_shuffle_speed < 500 ) return; if ( --p_sys->i_auto_shuffle_countdown_val > 0 ) return; /* delay reached, preset next delay and proceed with puzzle_auto_shuffle */ p_sys->i_auto_shuffle_countdown_val = init_countdown(p_sys->s_current_param.i_auto_shuffle_speed); /* random piece to be moved */ int32_t i_start = ((unsigned)vlc_mrand48()) % p_sys->s_allocated.i_pieces_nbr; for (uint32_t i_l = 0; i_l < p_sys->s_allocated.i_pieces_nbr; i_l++){ int32_t i = ( i_l + i_start ) % p_sys->s_allocated.i_pieces_nbr; /* find one piece which is part of one group */ if ( p_sys->pi_group_qty[p_sys->ps_pieces[i].i_group_ID] > 1 ) { /* find an empty group to be used by this dismantled piece */ uint32_t i_new_group; for ( i_new_group = 0 ; i_new_group < p_sys->s_allocated.i_pieces_nbr ; i_new_group ++ ) if ( p_sys->pi_group_qty[i_new_group] == 0 ) break; p_sys->ps_pieces[i].i_group_ID = i_new_group; p_sys->ps_pieces[i].b_finished = false; /* random rotate & mirror */ switch ( p_sys->s_current_param.i_rotate ) { case 1: 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 ); break; case 2: 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 ); break; case 3: 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 ); break; } /* random mvt */ p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_x = p_sys->ps_desk_planes[0].i_border_width + ( (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) + p_sys->ps_pieces[i].ps_piece_in_plane[0].i_width / 2 * ( 1 - p_sys->ps_pieces[i].i_step_x_x ) - (p_sys->ps_pieces[i].ps_piece_in_plane[0].i_lines / 2) * p_sys->ps_pieces[i].i_step_y_x; p_sys->ps_pieces[i].ps_piece_in_plane[0].i_actual_y = p_sys->ps_desk_planes[0].i_border_lines + ( (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) + p_sys->ps_pieces[i].ps_piece_in_plane[0].i_lines / 2 * ( 1 - p_sys->ps_pieces[i].i_step_y_y ) - (p_sys->ps_pieces[i].ps_piece_in_plane[0].i_width / 2) * p_sys->ps_pieces[i].i_step_x_y; /* redefine shapes */ uint32_t i_left_pce = 0; uint32_t i_right_pce = 6; uint32_t i_top_pce = 2; uint32_t i_btm_pce = 4; uint32_t i_pce = 0; for (int32_t i_row = 0; i_row < p_sys->s_allocated.i_rows; i_row++) for (int32_t i_col = 0; i_col < p_sys->s_allocated.i_cols; i_col++) { if (p_sys->ps_pieces[i].i_original_row == p_sys->ps_pieces[i_pce].i_original_row) { if (p_sys->ps_pieces[i].i_original_col == p_sys->ps_pieces[i_pce].i_original_col - 1) i_right_pce = i_pce; else if (p_sys->ps_pieces[i].i_original_col == p_sys->ps_pieces[i_pce].i_original_col + 1) i_left_pce = i_pce; } else if (p_sys->ps_pieces[i].i_original_col == p_sys->ps_pieces[i_pce].i_original_col) { if (p_sys->ps_pieces[i].i_original_row == p_sys->ps_pieces[i_pce].i_original_row - 1) i_btm_pce = i_pce; else if (p_sys->ps_pieces[i].i_original_row == p_sys->ps_pieces[i_pce].i_original_row + 1) i_top_pce = i_pce; } i_pce++; } if ((p_sys->ps_pieces[i].i_left_shape == 0) && (p_sys->ps_pieces[i].i_original_col != 0)) { p_sys->ps_pieces[i_left_pce].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01); p_sys->ps_pieces[i].i_left_shape = (p_sys->ps_pieces[i_left_pce].i_right_shape - 6 ) ^ 0x01; } 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)) { p_sys->ps_pieces[i].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01); p_sys->ps_pieces[i_right_pce].i_left_shape = (p_sys->ps_pieces[i].i_right_shape - 6 ) ^ 0x01; } if ((p_sys->ps_pieces[i].i_top_shape == 2) && (p_sys->ps_pieces[i].i_original_row != 0)) { p_sys->ps_pieces[i_top_pce].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01); p_sys->ps_pieces[i].i_top_shape = (p_sys->ps_pieces[i_top_pce].i_btm_shape - 2 ) ^ 0x01; } 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)) { p_sys->ps_pieces[i].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01); p_sys->ps_pieces[i_btm_pce].i_top_shape = (p_sys->ps_pieces[i].i_btm_shape - 2 ) ^ 0x01; } puzzle_calculate_corners( p_filter, i ); break; } } }
/***************************************************************************** * puzzle_bake_piece: compute data dedicated to each piece *****************************************************************************/ int puzzle_bake_piece( filter_t *p_filter) { int i_ret = puzzle_allocate_ps_pieces( p_filter); if (i_ret != VLC_SUCCESS) return i_ret; filter_sys_t *p_sys = p_filter->p_sys; /* generates random pi_order array */ i_ret = puzzle_shuffle( p_filter ); if (i_ret != VLC_SUCCESS) return i_ret; int32_t i = 0; for (int32_t row = 0; row < p_sys->s_allocated.i_rows; row++) { for (int32_t col = 0; col < p_sys->s_allocated.i_cols; col++) { int32_t orow = row; int32_t ocol = col; if (p_sys->pi_order != NULL) { orow = p_sys->pi_order[i] / (p_sys->s_allocated.i_cols); ocol = p_sys->pi_order[i] % (p_sys->s_allocated.i_cols); } p_sys->ps_pieces[i].i_original_row = orow; p_sys->ps_pieces[i].i_original_col = ocol; /* set bottom and right shapes */ p_sys->ps_pieces[i].i_left_shape = 0; p_sys->ps_pieces[i].i_top_shape = 2; p_sys->ps_pieces[i].i_btm_shape = 4; p_sys->ps_pieces[i].i_right_shape = 6; if (p_sys->s_allocated.i_shape_size > 0) { if (orow < p_sys->s_allocated.i_rows - 1) p_sys->ps_pieces[i].i_btm_shape = 4 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01); if (ocol < p_sys->s_allocated.i_cols - 1) p_sys->ps_pieces[i].i_right_shape = 6 + 8 + 8*(( (unsigned) vlc_mrand48()) % ( SHAPES_QTY ) ) + (vlc_mrand48() & 0x01); } /* set piece data */ p_sys->ps_pieces[i].i_actual_angle = 0; p_sys->ps_pieces[i].b_overlap = false; p_sys->ps_pieces[i].i_actual_mirror = +1; p_sys->ps_pieces[i].b_finished = ((ocol == col) && (orow == row)); p_sys->ps_pieces[i].i_group_ID = i; /* add small random offset to location */ int32_t i_rand_x = 0; int32_t i_rand_y = 0; if (p_sys->s_current_param.b_advanced) { 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; 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; } /* copy related puzzle data to piece data */ if (p_sys->ps_puzzle_array != NULL) { for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) { p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_width = p_sys->ps_puzzle_array[row][col][i_plane].i_width; p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_lines = p_sys->ps_puzzle_array[row][col][i_plane].i_lines; 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; 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; 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 * p_sys->ps_desk_planes[i_plane].i_width / p_sys->ps_desk_planes[0].i_width; 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 * p_sys->ps_desk_planes[i_plane].i_lines / p_sys->ps_desk_planes[0].i_lines; if (i_plane == 0) { p_sys->ps_pieces[i].i_OLx = p_sys->ps_pieces[i].ps_piece_in_plane[0].i_original_x; p_sys->ps_pieces[i].i_OTy = p_sys->ps_pieces[i].ps_piece_in_plane[0].i_original_y; 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; 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; puzzle_calculate_corners( p_filter, i ); } } } i++; } } /* left and top shapes are based on negative right and bottom ones */ puzzle_set_left_top_shapes( p_filter); /* add random rotation to each piece */ puzzle_random_rotate( p_filter); return VLC_SUCCESS; }
/** * Filter a picture */ picture_t *Filter( filter_t *p_filter, picture_t *p_pic_in ) { if( !p_pic_in || !p_filter) return NULL; const video_format_t *p_fmt_in = &p_filter->fmt_in.video; filter_sys_t *p_sys = p_filter->p_sys; picture_t *p_pic_out = filter_NewPicture( p_filter ); if( !p_pic_out ) { picture_Release( p_pic_in ); return NULL; } int i_ret = 0; p_sys->b_bake_request = false; if ((p_sys->pi_order == NULL) || (p_sys->ps_desk_planes == NULL) || (p_sys->ps_pict_planes == NULL) || (p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL)) p_sys->b_init = false; if ((p_sys->ps_pieces_shapes == NULL) && p_sys->s_current_param.b_advanced && (p_sys->s_current_param.i_shape_size != 0)) p_sys->b_init = false; /* assert initialized & allocated data match with current frame characteristics */ if ( p_sys->s_allocated.i_planes != p_pic_out->i_planes) p_sys->b_init = false; p_sys->s_current_param.i_planes = p_pic_out->i_planes; if (p_sys->ps_pict_planes != NULL) { for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) { if ( (p_sys->ps_pict_planes[i_plane].i_lines != p_pic_in->p[i_plane].i_visible_lines) || (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) || (p_sys->ps_desk_planes[i_plane].i_lines != p_pic_out->p[i_plane].i_visible_lines) || (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) ) p_sys->b_init = false; } } p_sys->s_current_param.i_pict_width = (int) p_pic_in->p[0].i_visible_pitch / p_pic_in->p[0].i_pixel_pitch; p_sys->s_current_param.i_pict_height = (int) p_pic_in->p[0].i_visible_lines; p_sys->s_current_param.i_desk_width = (int) p_pic_out->p[0].i_visible_pitch / p_pic_out->p[0].i_pixel_pitch; p_sys->s_current_param.i_desk_height = (int) p_pic_out->p[0].i_visible_lines; /* assert no mismatch between sizes */ if ( p_sys->s_current_param.i_pict_width != p_sys->s_current_param.i_desk_width || p_sys->s_current_param.i_pict_height != p_sys->s_current_param.i_desk_height || p_sys->s_current_param.i_pict_width != (int) p_fmt_in->i_visible_width || p_sys->s_current_param.i_pict_height != (int) p_fmt_in->i_visible_height ) { picture_Release(p_pic_in); picture_Release(p_pic_out); return NULL; } vlc_mutex_lock( &p_sys->lock ); /* check if we have to compute initial data */ if ( p_sys->b_change_param || p_sys->b_bake_request || !p_sys->b_init ) { if ( p_sys->s_allocated.i_rows != p_sys->s_new_param.i_rows || p_sys->s_allocated.i_cols != p_sys->s_new_param.i_cols || p_sys->s_allocated.i_rotate != p_sys->s_new_param.i_rotate || p_sys->s_allocated.i_mode != p_sys->s_new_param.i_mode || p_sys->b_bake_request || !p_sys->b_init ) { p_sys->b_bake_request = true; p_sys->b_init = false; p_sys->b_shuffle_rqst = true; p_sys->b_shape_init = false; } if ( p_sys->s_current_param.i_border != p_sys->s_new_param.i_border || p_sys->s_current_param.i_shape_size != p_sys->s_new_param.i_shape_size ) { p_sys->b_bake_request = true; p_sys->b_shape_init = false; } /* depending on the game selected, set associated internal flags */ switch ( p_sys->s_new_param.i_mode ) { case 0: /* jigsaw puzzle */ p_sys->s_new_param.b_advanced = true; p_sys->s_new_param.b_blackslot = false; p_sys->s_new_param.b_near = false; break; case 1: /* sliding puzzle */ p_sys->s_new_param.b_advanced = false; p_sys->s_new_param.b_blackslot = true; p_sys->s_new_param.b_near = true; break; case 2: /* swap puzzle */ p_sys->s_new_param.b_advanced = false; p_sys->s_new_param.b_blackslot = false; p_sys->s_new_param.b_near = true; break; case 3: /* exchange puzzle */ p_sys->s_new_param.b_advanced = false; p_sys->s_new_param.b_blackslot = false; p_sys->s_new_param.b_near = false; break; } p_sys->s_current_param.i_mode = p_sys->s_new_param.i_mode; if ( p_sys->s_current_param.b_blackslot != p_sys->s_new_param.b_blackslot && p_sys->i_selected == NO_PCE && p_sys->s_current_param.b_blackslot ) p_sys->i_selected = 0; if ( p_sys->s_current_param.i_auto_shuffle_speed != p_sys->s_new_param.i_auto_shuffle_speed ) p_sys->i_auto_shuffle_countdown_val = init_countdown(p_sys->s_new_param.i_auto_shuffle_speed); if ( p_sys->s_current_param.i_auto_solve_speed != p_sys->s_new_param.i_auto_solve_speed ) p_sys->i_auto_solve_countdown_val = init_countdown(p_sys->s_current_param.i_auto_solve_speed); p_sys->s_current_param.i_rows = p_sys->s_new_param.i_rows; p_sys->s_current_param.i_cols = p_sys->s_new_param.i_cols; p_sys->s_current_param.i_pieces_nbr = p_sys->s_current_param.i_rows * p_sys->s_current_param.i_cols; p_sys->s_current_param.b_advanced = p_sys->s_new_param.b_advanced; if (!p_sys->s_new_param.b_advanced) { p_sys->s_current_param.b_blackslot = p_sys->s_new_param.b_blackslot; p_sys->s_current_param.b_near = p_sys->s_new_param.b_near || p_sys->s_new_param.b_blackslot; p_sys->s_current_param.i_border = 0; p_sys->s_current_param.b_preview = false; p_sys->s_current_param.i_preview_size= 0; p_sys->s_current_param.i_shape_size = 0; p_sys->s_current_param.i_auto_shuffle_speed = 0; p_sys->s_current_param.i_auto_solve_speed = 0; p_sys->s_current_param.i_rotate = 0; } else { p_sys->s_current_param.b_blackslot = false; p_sys->s_current_param.b_near = false; p_sys->s_current_param.i_border = p_sys->s_new_param.i_border; p_sys->s_current_param.b_preview = p_sys->s_new_param.b_preview; p_sys->s_current_param.i_preview_size = p_sys->s_new_param.i_preview_size; p_sys->s_current_param.i_shape_size = p_sys->s_new_param.i_shape_size; p_sys->s_current_param.i_auto_shuffle_speed = p_sys->s_new_param.i_auto_shuffle_speed; p_sys->s_current_param.i_auto_solve_speed = p_sys->s_new_param.i_auto_solve_speed; p_sys->s_current_param.i_rotate = p_sys->s_new_param.i_rotate; } p_sys->b_change_param = false; } vlc_mutex_unlock( &p_sys->lock ); /* generate initial puzzle data when needed */ if ( p_sys->b_bake_request ) { if (!p_sys->b_shuffle_rqst) { /* here we have to keep the same position * we have to save locations before generating new data */ save_game_t *ps_save_game = puzzle_save(p_filter); if (!ps_save_game) return CopyInfoAndRelease( p_pic_out, p_pic_in ); i_ret = puzzle_bake( p_filter, p_pic_out, p_pic_in ); if ( i_ret != VLC_SUCCESS ) { free(ps_save_game->ps_pieces); free(ps_save_game); return CopyInfoAndRelease( p_pic_out, p_pic_in ); } puzzle_load( p_filter, ps_save_game); free(ps_save_game->ps_pieces); free(ps_save_game); } else { i_ret = puzzle_bake( p_filter, p_pic_out, p_pic_in ); if ( i_ret != VLC_SUCCESS ) return CopyInfoAndRelease( p_pic_out, p_pic_in ); } } /* shuffle the desk and generate pieces data */ if ( p_sys->b_shuffle_rqst && p_sys->b_init ) { i_ret = puzzle_bake_piece ( p_filter ); if (i_ret != VLC_SUCCESS) return CopyInfoAndRelease( p_pic_out, p_pic_in ); } /* preset output pic */ if ( !p_sys->b_bake_request && !p_sys->b_shuffle_rqst && p_sys->b_init && !p_sys->b_finished ) puzzle_preset_desk_background(p_pic_out, 0, 127, 127); else { /* copy src to dst during init & bake process */ for( uint8_t i_plane = 0; i_plane < p_pic_out->i_planes; i_plane++ ) memcpy( p_pic_out->p[i_plane].p_pixels, p_pic_in->p[i_plane].p_pixels, p_pic_in->p[i_plane].i_pitch * (int32_t) p_pic_in->p[i_plane].i_visible_lines ); } vlc_mutex_lock( &p_sys->pce_lock ); /* manage the game, adjust locations, groups and regenerate some corrupted data if any */ for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 ) && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++) { puzzle_solve_pces_accuracy( p_filter ); } for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 ) && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++) { puzzle_solve_pces_group( p_filter ); } if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ) puzzle_count_pce_group( p_filter); if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ) { i_ret = puzzle_sort_layers( p_filter); if (i_ret != VLC_SUCCESS) { vlc_mutex_unlock( &p_sys->pce_lock ); return CopyInfoAndRelease( p_pic_out, p_pic_in ); } } for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 24 ) && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++) { p_sys->i_calc_corn_loop++; p_sys->i_calc_corn_loop %= p_sys->s_allocated.i_pieces_nbr; puzzle_calculate_corners( p_filter, p_sys->i_calc_corn_loop ); } /* computer moves some piece depending on auto_solve and auto_shuffle param */ if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->ps_puzzle_array != NULL && p_sys->s_current_param.b_advanced ) { puzzle_auto_shuffle( p_filter ); puzzle_auto_solve( p_filter ); } vlc_mutex_unlock( &p_sys->pce_lock ); /* draw output pic */ if ( !p_sys->b_bake_request && p_sys->b_init && p_sys->ps_puzzle_array != NULL ) { puzzle_draw_borders(p_filter, p_pic_in, p_pic_out); p_sys->i_pointed_pce = NO_PCE; puzzle_draw_pieces(p_filter, p_pic_in, p_pic_out); /* when puzzle_draw_pieces() has not updated p_sys->i_pointed_pce, * use puzzle_find_piece to define the piece pointed by the mouse */ if (p_sys->i_pointed_pce == NO_PCE) p_sys->i_mouse_drag_pce = puzzle_find_piece( p_filter, p_sys->i_mouse_x, p_sys->i_mouse_y, -1); else p_sys->i_mouse_drag_pce = p_sys->i_pointed_pce; if (p_sys->s_current_param.b_preview ) puzzle_draw_preview(p_filter, p_pic_in, p_pic_out); /* highlight the selected piece when not playing jigsaw mode */ if ( p_sys->i_selected != NO_PCE && !p_sys->s_current_param.b_blackslot && !p_sys->s_current_param.b_advanced ) { int32_t c = (p_sys->i_selected % p_sys->s_allocated.i_cols); int32_t r = (p_sys->i_selected / p_sys->s_allocated.i_cols); puzzle_draw_rectangle(p_pic_out, p_sys->ps_puzzle_array[r][c][0].i_x, p_sys->ps_puzzle_array[r][c][0].i_y, p_sys->ps_puzzle_array[r][c][0].i_width, p_sys->ps_puzzle_array[r][c][0].i_lines, 255, 127, 127); } /* draw the blackslot when playing sliding puzzle mode */ if ( p_sys->i_selected != NO_PCE && p_sys->s_current_param.b_blackslot && !p_sys->s_current_param.b_advanced ) { int32_t c = (p_sys->i_selected % p_sys->s_allocated.i_cols); int32_t r = (p_sys->i_selected / p_sys->s_allocated.i_cols); puzzle_fill_rectangle(p_pic_out, p_sys->ps_puzzle_array[r][c][0].i_x, p_sys->ps_puzzle_array[r][c][0].i_y, p_sys->ps_puzzle_array[r][c][0].i_width, p_sys->ps_puzzle_array[r][c][0].i_lines, 0, 127, 127); } /* Draw the 'puzzle_shuffle' button if the puzzle is finished */ if ( p_sys->b_finished ) puzzle_draw_sign(p_pic_out, 0, 0, SHUFFLE_WIDTH, SHUFFLE_LINES, ppsz_shuffle_button, false); /* draw an arrow at mouse pointer to indicate current action (rotation...) */ if ((p_sys->i_mouse_drag_pce != NO_PCE) && !p_sys->b_mouse_drag && !p_sys->b_finished && p_sys->s_current_param.b_advanced ) { vlc_mutex_lock( &p_sys->pce_lock ); int32_t i_delta_x; if (p_sys->s_current_param.i_rotate != 3) i_delta_x = 0; else if ( (p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_actual_angle & 1) == 0) i_delta_x = p_sys->ps_desk_planes[0].i_pce_max_width / 6; else i_delta_x = p_sys->ps_desk_planes[0].i_pce_max_lines / 6; if (p_sys->s_current_param.i_rotate == 0) p_sys->i_mouse_action = 0; else if (p_sys->s_current_param.i_rotate == 1) p_sys->i_mouse_action = 2; else if ( p_sys->i_mouse_x >= ( p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_center_x + i_delta_x) ) p_sys->i_mouse_action = -1; /* rotate counterclockwise */ else if ( p_sys->i_mouse_x <= ( p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_center_x - i_delta_x) ) p_sys->i_mouse_action = +1; else p_sys->i_mouse_action = 4; /* center click: only mirror */ if ( p_sys->i_mouse_action == +1 ) puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH, p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_rot_arrow_sign, false); else if ( p_sys->i_mouse_action == -1 ) puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH, p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_rot_arrow_sign, true); else if ( p_sys->i_mouse_action == 4 ) puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH, p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_mir_arrow_sign, false); vlc_mutex_unlock( &p_sys->pce_lock ); } } return CopyInfoAndRelease( p_pic_out, p_pic_in ); }