[vlc-devel] [PATCH 3/7] Puzzle: piece management and drawing
Vianney Boyer
vlcvboyer at gmail.com
Mon Apr 15 20:45:04 CEST 2013
From: Vianney BOYER <vlcvboyer at gmail.com>
Date: Mon, 15 Apr 2013 20:24:45 +0200
Subject: [PATCH 3/7] Puzzle: piece management and drawing
Please find the updated patch below taking into account the following
comments:
>Those are leaked in all your error cases.
Fixed
>why this if? just return i_ret. (Maybe found in other functions)
Cleaned
(Because I had another line in a previous version.)
>I don't have the time right now to check but I suppose that (ps_piece_shape->ps_piece_shape_row should be freed in another function, shouldn't it be set to NULL to avoid potential double free?
Sure, updated
---
modules/video_filter/puzzle_pce.c | 978
+++++++++++++++++++++++++++++++++++++
modules/video_filter/puzzle_pce.h | 112 +++++
2 files changed, 1090 insertions(+)
create mode 100644 modules/video_filter/puzzle_pce.c
create mode 100644 modules/video_filter/puzzle_pce.h
diff --git a/modules/video_filter/puzzle_pce.c
b/modules/video_filter/puzzle_pce.c
new file mode 100644
index 0000000..de5d163
--- /dev/null
+++ b/modules/video_filter/puzzle_pce.c
@@ -0,0 +1,978 @@
+/*****************************************************************************
+ * puzzle_pce.c : Puzzle game filter - pieces functions
+
*****************************************************************************
+ * Copyright (C) 2013 Vianney Boyer
+ * $Id$
+ *
+ * Author: Vianney Boyer <vlcvboyer -at- gmail -dot- com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+
*****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+
*****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <math.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_filter.h>
+#include <vlc_rand.h>
+
+#include "filter_picture.h"
+
+#include "puzzle_bezier.h"
+#include "puzzle_lib.h"
+#include "puzzle_pce.h"
+
+#define SHAPES_QTY 20
+#define PIECE_TYPE_NBR (4*2*(1+SHAPES_QTY))
+
+/*****************************************************************************
+ * puzzle_bake_pieces_shapes: allocate and compute shapes
+
*****************************************************************************/
+int puzzle_bake_pieces_shapes( filter_t *p_filter)
+{
+/* note:
+ * piece_shape_t **ps_pieces_shapes; * array [each piece type
(PCE_TYPE_NBR * 4 ( * negative ): top, left,right,btm)][each plane] of
piece definition
+ * 0 => left border
+ * 1 => left border (negative, never used)
+ * 2 => top border
+ * .....
+ * 8 => bezier left
+ * 9 => bezier left negative
+ * 10 => bezier top
+ * 11 => bezier top negative
+ * 12 => bezier btm
+ * 13 => bezier btm negative
+ * 14 => bezier right
+ * 15 => bezier right negative
+ * .....
+ */
+
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ puzzle_free_ps_pieces_shapes(p_filter);
+ p_sys->ps_pieces_shapes = malloc( sizeof( piece_shape_t *) *
PIECE_TYPE_NBR );
+ if( !p_sys->ps_pieces_shapes )
+ return VLC_ENOMEM;
+
+ for (int32_t i_piece = 0; i_piece < PIECE_TYPE_NBR; i_piece++) {
+ p_sys->ps_pieces_shapes[i_piece] = malloc( sizeof(
piece_shape_t) * p_sys->s_allocated.i_planes );
+ if( !p_sys->ps_pieces_shapes[i_piece] )
+ return VLC_ENOMEM;
+ for (uint8_t i_plane = 0; i_plane <
p_filter->p_sys->s_allocated.i_planes; i_plane++) {
+ p_sys->ps_pieces_shapes[i_piece][i_plane].i_row_nbr = 0;
+ p_sys->ps_pieces_shapes[i_piece][i_plane].ps_piece_shape_row = NULL;
+ }
+ }
+
+ int32_t i_currect_shape = 0;
+
+ for (uint8_t i_plane = 0; i_plane <
p_filter->p_sys->s_allocated.i_planes; i_plane++) {
+ int i_ret;
+ i_ret = puzzle_generate_sect_border( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+0][i_plane], i_plane,
puzzle_SHAPE_LEFT);
+ if (i_ret != VLC_SUCCESS) return i_ret;
+ i_ret = puzzle_generate_sect_border( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+1][i_plane], i_plane,
puzzle_SHAPE_LEFT);
+ if (i_ret != VLC_SUCCESS) return i_ret;
+ i_ret = puzzle_generate_sect_border( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+2][i_plane], i_plane,
puzzle_SHAPE_TOP);
+ if (i_ret != VLC_SUCCESS) return i_ret;
+ i_ret = puzzle_generate_sect_border( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+3][i_plane], i_plane,
puzzle_SHAPE_TOP);
+ if (i_ret != VLC_SUCCESS) return i_ret;
+ i_ret = puzzle_generate_sect_border( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+4][i_plane], i_plane,
puzzle_SHAPE_BTM);
+ if (i_ret != VLC_SUCCESS) return i_ret;
+ i_ret = puzzle_generate_sect_border( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+5][i_plane], i_plane,
puzzle_SHAPE_BTM);
+ if (i_ret != VLC_SUCCESS) return i_ret;
+ i_ret = puzzle_generate_sect_border( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+6][i_plane], i_plane,
puzzle_SHAPE_RIGHT);
+ if (i_ret != VLC_SUCCESS) return i_ret;
+ i_ret = puzzle_generate_sect_border( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+7][i_plane], i_plane,
puzzle_SHAPE_RIGHT);
+ if (i_ret != VLC_SUCCESS) return i_ret;
+ }
+
+ i_currect_shape += 8;
+
+ int32_t i_width = p_sys->ps_desk_planes[0].i_pce_max_width;
+ int32_t i_lines = p_sys->ps_desk_planes[0].i_pce_max_lines;
+
+ for (int32_t i_shape = 0; i_shape<SHAPES_QTY; i_shape++) {
+
+ point_t *ps_scale_pts_H = puzzle_scale_curve_H(i_width,
i_lines, 7, p_sys->ps_bezier_pts_H[i_shape],
p_sys->s_allocated.i_shape_size);
+ point_t *ps_scale_pts_V = puzzle_H_2_scale_curve_V(i_width,
i_lines, 7, p_sys->ps_bezier_pts_H[i_shape],
p_sys->s_allocated.i_shape_size);
+ point_t *ps_neg_pts_H = puzzle_curve_H_2_negative(7,
ps_scale_pts_H);
+ point_t *ps_neg_pts_V = puzzle_curve_V_2_negative(7,
ps_scale_pts_V);
+
+ if (!ps_scale_pts_H || !ps_scale_pts_V || !ps_neg_pts_H ||
!ps_neg_pts_V)
+ return VLC_EGENERIC;
+
+ int i_ret;
+ for (uint8_t i_plane = 0; i_plane <
p_filter->p_sys->s_allocated.i_planes; i_plane++) {
+ i_ret = puzzle_generate_sect_bezier( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape][i_plane], 7, ps_scale_pts_V,
i_plane, puzzle_SHAPE_LEFT);
+ if (i_ret != VLC_SUCCESS) break;
+ i_ret = puzzle_generate_sect_bezier( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+1][i_plane], 7, ps_neg_pts_V,
i_plane, puzzle_SHAPE_LEFT);
+ if (i_ret != VLC_SUCCESS) break;
+ i_ret = puzzle_generate_sect_bezier( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+2][i_plane], 7, ps_scale_pts_H,
i_plane, puzzle_SHAPE_TOP);
+ if (i_ret != VLC_SUCCESS) break;
+ i_ret = puzzle_generate_sect_bezier( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+3][i_plane], 7, ps_neg_pts_H,
i_plane, puzzle_SHAPE_TOP);
+ if (i_ret != VLC_SUCCESS) break;
+
+ i_ret = puzzle_generate_sectTop2Btm( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+4][i_plane],
&p_sys->ps_pieces_shapes[i_currect_shape+2][i_plane], i_plane);
+ if (i_ret != VLC_SUCCESS) break;
+ i_ret = puzzle_generate_sectTop2Btm( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+5][i_plane],
&p_sys->ps_pieces_shapes[i_currect_shape+3][i_plane], i_plane);
+ if (i_ret != VLC_SUCCESS) break;
+ i_ret = puzzle_generate_sectLeft2Right( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+6][i_plane],
&p_sys->ps_pieces_shapes[i_currect_shape][i_plane], i_plane);
+ if (i_ret != VLC_SUCCESS) break;
+ i_ret = puzzle_generate_sectLeft2Right( p_filter,
&p_sys->ps_pieces_shapes[i_currect_shape+7][i_plane],
&p_sys->ps_pieces_shapes[i_currect_shape+1][i_plane], i_plane);
+ if (i_ret != VLC_SUCCESS) break;
+ }
+
+ free(ps_scale_pts_H);
+ free(ps_scale_pts_V);
+ free(ps_neg_pts_H);
+ free(ps_neg_pts_V);
+
+ if (i_ret != VLC_SUCCESS) return i_ret;
+
+ i_currect_shape += 8;
+ }
+
+ p_sys->b_shape_init = true;
+
+ return VLC_SUCCESS;
+}
+
+/* free allocated shapes data */
+void puzzle_free_ps_pieces_shapes( filter_t *p_filter)
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ if (p_sys->ps_pieces_shapes == NULL)
+ return;
+
+ for (int32_t p = 0; p < p_sys->s_allocated.i_piece_types; p++) {
+ for (uint8_t i_plane = 0; i_plane <
p_sys->s_allocated.i_planes; i_plane++) {
+ for (int32_t r = 0; r <
p_sys->ps_pieces_shapes[p][i_plane].i_row_nbr; r++)
+ free(
p_sys->ps_pieces_shapes[p][i_plane].ps_piece_shape_row[r].ps_row_section );
+ free( p_sys->ps_pieces_shapes[p][i_plane].ps_piece_shape_row );
+ }
+ free( p_sys->ps_pieces_shapes[p] );
+ }
+ free( p_sys->ps_pieces_shapes );
+ p_sys->ps_pieces_shapes = NULL;
+}
+
+/*****************************************************************************
+ * puzzle_find_piece: use piece corners to find the piece selected
+ * by mouse cursor
+
*****************************************************************************/
+int puzzle_find_piece( filter_t *p_filter, int32_t i_x, int32_t i_y,
int32_t i_except) {
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
+ piece_t *ps_current_piece = &p_sys->ps_pieces[i];
+ if (( ps_current_piece->i_min_x <= i_x ) &&
+ ( ps_current_piece->i_max_x >= i_x ) &&
+ ( ps_current_piece->i_min_y <= i_y ) &&
+ ( ps_current_piece->i_max_y >= i_y ) &&
+ ( (int32_t)i != i_except ) )
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*****************************************************************************
+ * puzzle_calculate_corners: calculate corners location & regen
geometry data
+
*****************************************************************************/
+void puzzle_calculate_corners( filter_t *p_filter, int32_t i_piece )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+ piece_t *ps_piece = &p_sys->ps_pieces[i_piece];
+
+ switch ( ps_piece->i_actual_angle)
+ {
+ case 0:
+ ps_piece->i_step_x_x = ps_piece->i_actual_mirror;
+ ps_piece->i_step_x_y = 0;
+ ps_piece->i_step_y_y = 1;
+ ps_piece->i_step_y_x = 0;
+ break;
+ case 1:
+ ps_piece->i_step_x_x = 0;
+ ps_piece->i_step_x_y = -ps_piece->i_actual_mirror; /* x offset
on original pict creates negative y offset on desk */
+ ps_piece->i_step_y_y = 0;
+ ps_piece->i_step_y_x = 1;
+ break;
+ case 2:
+ ps_piece->i_step_x_x = -ps_piece->i_actual_mirror;
+ ps_piece->i_step_x_y = 0;
+ ps_piece->i_step_y_y = -1;
+ ps_piece->i_step_y_x = 0;
+ break;
+ case 3:
+ ps_piece->i_step_x_x = 0;
+ ps_piece->i_step_x_y = ps_piece->i_actual_mirror;
+ ps_piece->i_step_y_y = 0;
+ ps_piece->i_step_y_x = -1;
+ break;
+ }
+
+ /* regen geometry */
+ for (uint8_t i_plane = 1; i_plane < p_sys->s_allocated.i_planes;
i_plane++) {
+ ps_piece->ps_piece_in_plane[i_plane].i_actual_x =
+ ps_piece->ps_piece_in_plane[0].i_actual_x *
p_sys->ps_desk_planes[i_plane].i_width / p_sys->ps_desk_planes[0].i_width;
+ ps_piece->ps_piece_in_plane[i_plane].i_actual_y =
+ ps_piece->ps_piece_in_plane[0].i_actual_y *
p_sys->ps_desk_planes[i_plane].i_lines / p_sys->ps_desk_planes[0].i_lines;
+ }
+
+ /* regen location of grabed piece's corners */
+ int32_t i_width = ps_piece->ps_piece_in_plane[0].i_width;
+ int32_t i_lines = ps_piece->ps_piece_in_plane[0].i_lines;
+
+ ps_piece->i_TLx = ps_piece->ps_piece_in_plane[0].i_actual_x;
+ ps_piece->i_TLy = ps_piece->ps_piece_in_plane[0].i_actual_y;
+ ps_piece->i_TRx = ps_piece->i_TLx + ( i_width - 1 ) *
ps_piece->i_step_x_x;
+ ps_piece->i_TRy = ps_piece->i_TLy + ( i_width - 1 ) *
ps_piece->i_step_x_y;
+ ps_piece->i_BRx = ps_piece->i_TLx + ( i_width - 1 ) *
ps_piece->i_step_x_x + ( i_lines - 1 ) * ps_piece->i_step_y_x;
+ ps_piece->i_BRy = ps_piece->i_TLy + ( i_width - 1 ) *
ps_piece->i_step_x_y + ( i_lines - 1 ) * ps_piece->i_step_y_y;
+ ps_piece->i_BLx = ps_piece->i_TLx + ( i_lines - 1 ) *
ps_piece->i_step_y_x;
+ ps_piece->i_BLy = ps_piece->i_TLy + ( i_lines - 1 ) *
ps_piece->i_step_y_y;
+
+ ps_piece->i_max_x = __MAX( __MAX( ps_piece->i_TLx, ps_piece->i_TRx
), __MAX( ps_piece->i_BLx, ps_piece->i_BRx ) );
+ ps_piece->i_min_x = __MIN( __MIN( ps_piece->i_TLx, ps_piece->i_TRx
), __MIN( ps_piece->i_BLx, ps_piece->i_BRx ) );
+ ps_piece->i_max_y = __MAX( __MAX( ps_piece->i_TLy, ps_piece->i_TRy
), __MAX( ps_piece->i_BLy, ps_piece->i_BRy ) );
+ ps_piece->i_min_y = __MIN( __MIN( ps_piece->i_TLy, ps_piece->i_TRy
), __MIN( ps_piece->i_BLy, ps_piece->i_BRy ) );
+
+ ps_piece->i_center_x = ( ps_piece->i_max_x + ps_piece->i_min_x ) / 2;
+ ps_piece->i_center_y = ( ps_piece->i_max_y + ps_piece->i_min_y ) / 2;
+
+ int32_t pce_overlap = puzzle_find_piece( p_filter,
ps_piece->i_center_x, ps_piece->i_center_y, i_piece);
+
+ if ( ( pce_overlap != NO_PCE ) && (
p_sys->pi_group_qty[ps_piece->i_group_ID] == 1 ) )
+ ps_piece->b_overlap = true;
+}
+
+/*****************************************************************************
+ * 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 );
+ }
+}
+
+/*****************************************************************************
+ * 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 );
+ }
+ }
+}
+
+/*****************************************************************************
+ * draw straight rectangular piece in the specified plane
+
*****************************************************************************/
+void puzzle_drw_basic_pce_in_plane( filter_t *p_filter, picture_t
*p_pic_in, picture_t *p_pic_out, uint8_t i_plane, piece_t *ps_piece)
+{
+ /* basic version rectangular & angle = 0 */
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ if ((p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL)
|| (ps_piece == NULL))
+ return;
+
+ const int32_t i_src_pitch = p_pic_in->p[i_plane].i_pitch;
+ const int32_t i_dst_pitch = p_pic_out->p[i_plane].i_pitch;
+ const int32_t i_src_width = p_pic_in->p[i_plane].i_pitch /
p_pic_in->p[i_plane].i_pixel_pitch;
+ const int32_t i_dst_width = p_pic_out->p[i_plane].i_pitch /
p_pic_out->p[i_plane].i_pixel_pitch;
+ const int32_t i_pixel_pitch = p_pic_out->p[i_plane].i_pixel_pitch;
+ const int32_t i_src_visible_lines =
p_pic_in->p[i_plane].i_visible_lines;
+ const int32_t i_dst_visible_lines =
p_pic_out->p[i_plane].i_visible_lines;
+ uint8_t *p_src = p_pic_in->p[i_plane].p_pixels;
+ uint8_t *p_dst = p_pic_out->p[i_plane].p_pixels;
+
+ const int32_t i_desk_start_x =
ps_piece->ps_piece_in_plane[i_plane].i_actual_x;
+ const int32_t i_desk_start_y =
ps_piece->ps_piece_in_plane[i_plane].i_actual_y;
+ const int32_t i_pic_start_x =
ps_piece->ps_piece_in_plane[i_plane].i_original_x;
+ const int32_t i_pic_start_y =
ps_piece->ps_piece_in_plane[i_plane].i_original_y;
+ const int32_t i_width = ps_piece->ps_piece_in_plane[i_plane].i_width;
+ const int32_t i_lines = ps_piece->ps_piece_in_plane[i_plane].i_lines;
+
+ const int32_t i_ofs_x = __MAX(0,
__MAX(-i_desk_start_x,-i_pic_start_x));
+ const int32_t i_count_x = i_width - __MAX(0, __MAX(i_desk_start_x +
i_width - i_dst_width, i_pic_start_x + i_width - i_src_width ));
+ const int32_t i_ofs_y = __MAX(0,
__MAX(-i_desk_start_y,-i_pic_start_y));
+ const int32_t i_count_y = i_lines - __MAX(0, __MAX(i_desk_start_y +
i_lines - i_dst_visible_lines, i_pic_start_y + i_lines -
i_src_visible_lines ));
+
+ for (int32_t i_y = i_ofs_y; i_y < i_count_y; i_y++) {
+ memcpy( p_dst + (i_desk_start_y + i_y) * i_dst_pitch + (
i_desk_start_x + i_ofs_x ) * i_pixel_pitch,
+ p_src + (i_pic_start_y + i_y) * i_src_pitch + (
i_pic_start_x + i_ofs_x ) * i_pixel_pitch,
+ ( i_count_x - i_ofs_x ) * i_pixel_pitch );
+ }
+
+ return;
+}
+
+/*****************************************************************************
+ * draw oriented rectangular piece in the specified plane
+
*****************************************************************************/
+void puzzle_drw_adv_pce_in_plane( filter_t *p_filter, picture_t
*p_pic_in, picture_t *p_pic_out, uint8_t i_plane, piece_t *ps_piece)
+{
+ /* here we still have rectangular shape but angle is not 0 */
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ if ((p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL)
|| (ps_piece == NULL))
+ return;
+
+ const int32_t i_src_pitch = p_pic_in->p[i_plane].i_pitch;
+ const int32_t i_dst_pitch = p_pic_out->p[i_plane].i_pitch;
+ const int32_t i_src_width = p_pic_in->p[i_plane].i_pitch /
p_pic_in->p[i_plane].i_pixel_pitch;
+ const int32_t i_dst_width = p_pic_out->p[i_plane].i_pitch /
p_pic_out->p[i_plane].i_pixel_pitch;
+ const int32_t i_pixel_pitch = p_pic_out->p[i_plane].i_pixel_pitch;
+ const int32_t i_src_visible_lines =
p_pic_in->p[i_plane].i_visible_lines;
+ const int32_t i_dst_visible_lines =
p_pic_out->p[i_plane].i_visible_lines;
+ uint8_t *p_src = p_pic_in->p[i_plane].p_pixels;
+ uint8_t *p_dst = p_pic_out->p[i_plane].p_pixels;
+
+ const int32_t i_desk_start_x =
ps_piece->ps_piece_in_plane[i_plane].i_actual_x;
+ const int32_t i_desk_start_y =
ps_piece->ps_piece_in_plane[i_plane].i_actual_y;
+ const int32_t i_pic_start_x =
ps_piece->ps_piece_in_plane[i_plane].i_original_x;
+ const int32_t i_pic_start_y =
ps_piece->ps_piece_in_plane[i_plane].i_original_y;
+ const int32_t i_width = ps_piece->ps_piece_in_plane[i_plane].i_width;
+ const int32_t i_lines = ps_piece->ps_piece_in_plane[i_plane].i_lines;
+
+ for (int32_t i_y = 0; i_y < i_lines; i_y++) {
+ int32_t i_current_src_y = i_pic_start_y + i_y;
+
+ if ( ( i_current_src_y >= 0 ) && ( i_current_src_y <
i_src_visible_lines ) ) {
+ for (int32_t i_x = 0; i_x < i_width; i_x++) {
+ int32_t i_current_dst_x = i_desk_start_x + i_x *
ps_piece->i_step_x_x + i_y * ps_piece->i_step_y_x;
+ int32_t i_current_dst_y = i_desk_start_y + i_x *
ps_piece->i_step_x_y + i_y * ps_piece->i_step_y_y;
+ int32_t i_current_src_x = i_pic_start_x + i_x;
+
+ if ( ( i_current_dst_x >= 0 ) && ( i_current_src_x >= 0 )
+ && ( i_current_dst_x < i_dst_width ) && (
i_current_src_x < i_src_width )
+ && ( i_current_dst_y >= 0 ) && (
i_current_dst_y < i_dst_visible_lines ) )
+ {
+ memcpy( p_dst + i_current_dst_y * i_dst_pitch +
i_current_dst_x * i_pixel_pitch,
+ p_src + i_current_src_y * i_src_pitch +
i_current_src_x * i_pixel_pitch,
+ i_pixel_pitch );
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+/*****************************************************************************
+ * draw complex shape in the specified plane
+
*****************************************************************************/
+void puzzle_drw_complex_pce_in_plane( filter_t *p_filter, picture_t
*p_pic_in, picture_t *p_pic_out, uint8_t i_plane, piece_t *ps_piece,
uint32_t i_pce)
+{
+ /* "puzzle" shape and maybe angle != 0 */
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ if ((p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL)
|| (ps_piece == NULL))
+ return;
+
+ const int32_t i_src_pitch = p_pic_in->p[i_plane].i_pitch;
+ const int32_t i_dst_pitch = p_pic_out->p[i_plane].i_pitch;
+ const int32_t i_src_width = p_pic_in->p[i_plane].i_pitch /
p_pic_in->p[i_plane].i_pixel_pitch;
+ const int32_t i_dst_width = p_pic_out->p[i_plane].i_pitch /
p_pic_out->p[i_plane].i_pixel_pitch;
+ const int32_t i_pixel_pitch = p_pic_out->p[i_plane].i_pixel_pitch;
+ const int32_t i_src_visible_lines =
p_pic_in->p[i_plane].i_visible_lines;
+ const int32_t i_dst_visible_lines =
p_pic_out->p[i_plane].i_visible_lines;
+ uint8_t *p_src = p_pic_in->p[i_plane].p_pixels;
+ uint8_t *p_dst = p_pic_out->p[i_plane].p_pixels;
+
+ const int32_t i_desk_start_x =
ps_piece->ps_piece_in_plane[i_plane].i_actual_x;
+ const int32_t i_desk_start_y =
ps_piece->ps_piece_in_plane[i_plane].i_actual_y;
+ const int32_t i_pic_start_x =
ps_piece->ps_piece_in_plane[i_plane].i_original_x;
+ const int32_t i_pic_start_y =
ps_piece->ps_piece_in_plane[i_plane].i_original_y;
+
+ piece_shape_t *ps_top_shape =
&p_sys->ps_pieces_shapes[ps_piece->i_top_shape][i_plane];
+ piece_shape_t *ps_btm_shape =
&p_sys->ps_pieces_shapes[ps_piece->i_btm_shape][i_plane];
+ piece_shape_t *ps_right_shape =
&p_sys->ps_pieces_shapes[ps_piece->i_right_shape][i_plane];
+ piece_shape_t *ps_left_shape =
&p_sys->ps_pieces_shapes[ps_piece->i_left_shape][i_plane];
+ piece_shape_t *ps_shape;
+
+ int32_t i_min_y = ps_top_shape->i_first_row_offset;
+ int32_t i_max_y = ps_btm_shape->i_first_row_offset +
ps_btm_shape->i_row_nbr - 1;
+
+ for (int32_t i_y = i_min_y; i_y <= i_max_y; i_y++) {
+ int32_t i_current_src_y = i_pic_start_y + i_y;
+
+ if ( ( i_current_src_y >= 0 ) && ( i_current_src_y <
i_src_visible_lines ) ) {
+ int32_t i_sect_start_x = 0;
+
+ /* process each sub shape (each quarter) */
+ for (int8_t i_shape=0; i_shape < 4; i_shape++) {
+ switch ( i_shape )
+ {
+ case 0:
+ ps_shape = ps_left_shape;
+ break;
+ case 1:
+ ps_shape = ps_top_shape;
+ break;
+ case 2:
+ ps_shape = ps_btm_shape;
+ break;
+ case 3:
+ ps_shape = ps_right_shape;
+ break;
+ }
+
+ int32_t i_r = i_y - ps_shape->i_first_row_offset;
+
+ if (i_r <0 || i_r >= ps_shape->i_row_nbr)
+ continue;
+
+ piece_shape_row_t *ps_piece_shape_row =
&ps_shape->ps_piece_shape_row[i_r];
+
+ for (int32_t i_s = 0; i_s <
ps_piece_shape_row->i_section_nbr; i_s++) {
+ uint8_t i_type =
ps_piece_shape_row->ps_row_section[i_s].i_type;
+ int32_t i_width =
ps_piece_shape_row->ps_row_section[i_s].i_width;
+ if (i_type == 0) {
+ /* copy pixel line from input image to puzzle
desk */
+ for (int32_t i_x = 0; i_x < i_width; i_x++) {
+ int32_t i_current_dst_x = i_desk_start_x +
(i_sect_start_x + i_x) * ps_piece->i_step_x_x + i_y * ps_piece->i_step_y_x;
+ int32_t i_current_dst_y = i_desk_start_y +
(i_sect_start_x + i_x) * ps_piece->i_step_x_y + i_y * ps_piece->i_step_y_y;
+ int32_t i_current_src_x = i_pic_start_x +
(i_sect_start_x + i_x);
+
+ if ( i_current_dst_x < 0 ||
i_current_dst_x >= i_dst_width
+ || i_current_src_x < 0 ||
i_current_src_x >= i_src_width
+ || i_current_dst_y < 0 ||
i_current_dst_y >= i_dst_visible_lines )
+ continue;
+
+ memcpy( p_dst + i_current_dst_y *
i_dst_pitch + i_current_dst_x * i_pixel_pitch,
+ p_src + i_current_src_y *
i_src_pitch + i_current_src_x * i_pixel_pitch,
+ i_pixel_pitch );
+
+ /* Check if mouse pointer is over this pixel
+ * Yes: set i_pointed_pce = current drawn piece
+ */
+ if ((i_plane == 0) && (p_sys->i_mouse_x ==
i_current_dst_x )
+ && (p_sys->i_mouse_y ==
i_current_dst_y ))
+ p_sys->i_pointed_pce = i_pce;
+ }
+ }
+ i_sect_start_x += i_width;
+ }
+ }
+ }
+ }
+
+ return;
+}
+
+/*****************************************************************************
+ * draw all puzzle pieces on the desk
+
*****************************************************************************/
+void puzzle_draw_pieces( filter_t *p_filter, picture_t *p_pic_in,
picture_t *p_pic_out)
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ if ((p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL))
+ return;
+
+ for( uint8_t i_plane = 0; i_plane < p_pic_out->i_planes; i_plane++ ) {
+ for ( int32_t i = p_sys->s_allocated.i_pieces_nbr-1; i >= 0 ;
i-- ) {
+ piece_t *ps_piece = &p_sys->ps_pieces[i];
+
+ if (!p_sys->s_current_param.b_advanced
+ || (ps_piece->i_actual_mirror == 1 &&
ps_piece->i_actual_angle == 0
+ && p_sys->s_current_param.i_shape_size == 0))
+ {
+ puzzle_drw_basic_pce_in_plane(p_filter, p_pic_in,
p_pic_out, i_plane, ps_piece);
+ }
+ else if ( ( p_sys->s_current_param.i_shape_size == 0) ||
!p_sys->b_shape_init
+ || (p_sys->ps_pieces_shapes == NULL) ||
(!p_sys->b_shape_init) )
+ {
+ puzzle_drw_adv_pce_in_plane(p_filter, p_pic_in,
p_pic_out, i_plane, ps_piece);
+ }
+ else {
+ puzzle_drw_complex_pce_in_plane(p_filter, p_pic_in,
p_pic_out, i_plane, ps_piece, i);
+ }
+ }
+ }
+
+ return;
+}
+
+/*****************************************************************************
+ * when generating shape data: determine limit between sectors to be drawn
+
*****************************************************************************/
+int32_t puzzle_diagonal_limit( filter_t *p_filter, int32_t i_y, bool
b_left, uint8_t i_plane )
+{
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ if (b_left ^ (i_y >= p_sys->ps_desk_planes[i_plane].i_pce_max_lines
/ 2))
+ return ( i_y * p_sys->ps_desk_planes[i_plane].i_pce_max_width)
/ p_sys->ps_desk_planes[i_plane].i_pce_max_lines;
+ else
+ return p_sys->ps_desk_planes[i_plane].i_pce_max_width - ( ( i_y
* p_sys->ps_desk_planes[i_plane].i_pce_max_width) /
p_sys->ps_desk_planes[i_plane].i_pce_max_lines);
+}
+
+#define MAX_SECT 10
+
+/*****************************************************************************
+ * generate data which will be used to draw each line of a piece sector
with
+ * flat border
+
*****************************************************************************/
+int puzzle_generate_sect_border( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_plane, uint8_t i_border)
+{
+ /* generate data required to draw a sector of border puzzle piece */
+ if (!ps_piece_shape)
+ return VLC_EGENERIC;
+
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ int32_t i_width = p_sys->ps_desk_planes[i_plane].i_pce_max_width;
+ int32_t i_lines = p_sys->ps_desk_planes[i_plane].i_pce_max_lines;
+
+ /* process each horizontal pixel lines */
+ int32_t i_min_y = (i_border != puzzle_SHAPE_BTM) ? 0 : floor(
i_lines / 2 );
+
+ int32_t i_nb_y = (i_border != puzzle_SHAPE_TOP)?
+ (i_lines - i_min_y) : (i_lines /2 - i_min_y);
+
+ /* allocate memory */
+ ps_piece_shape->i_row_nbr = i_nb_y;
+ ps_piece_shape->i_first_row_offset = i_min_y;
+ ps_piece_shape->ps_piece_shape_row = malloc( sizeof(
piece_shape_row_t ) * i_nb_y );
+ if (!ps_piece_shape->ps_piece_shape_row)
+ return VLC_ENOMEM;
+
+ for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++) {
+ uint8_t i_sect = 0;
+ int32_t pi_sects[MAX_SECT];
+ int32_t i_row = i_y - i_min_y;
+
+ /* ...fill from border to next junction */
+ switch (i_border)
+ {
+ case puzzle_SHAPE_TOP:
+ case puzzle_SHAPE_BTM:
+ pi_sects[i_sect] = puzzle_diagonal_limit( p_filter, i_y,
false, i_plane ) - 1
+ - (puzzle_diagonal_limit( p_filter, i_y,
true, i_plane ) - 1);
+ break;
+ case puzzle_SHAPE_RIGHT:
+ pi_sects[i_sect] = i_width - puzzle_diagonal_limit(
p_filter, i_y, false, i_plane );
+ break;
+ case puzzle_SHAPE_LEFT:
+ default:
+ pi_sects[i_sect] = puzzle_diagonal_limit( p_filter, i_y,
true, i_plane );
+ }
+ i_sect++;
+
+ /* ...allocate memory and copy final values */
+ ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_sect);
+ if (!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
+ for (uint8_t i=0; i<i_row;i++)
+ free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
+ free(ps_piece_shape->ps_piece_shape_row);
+ ps_piece_shape->ps_piece_shape_row = NULL;
+ return VLC_ENOMEM;
+ }
+
+ for (uint8_t i=0; i < i_sect; i++) {
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = i
% 2; /* 0 = fill ; 1 = offset */
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+ }
+ }
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * generate data which will be used to draw each line of a piece sector
based
+ * on bezier curve
+
*****************************************************************************/
+int puzzle_generate_sect_bezier( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_pts_nbr, point_t *ps_pt, uint8_t i_plane,
uint8_t i_border)
+{
+ /* generate data required to draw a sector of puzzle piece using
bezier shape */
+ if ((!ps_pt) || (!ps_piece_shape))
+ return VLC_EGENERIC;
+
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ int32_t i_width = p_sys->ps_desk_planes[i_plane].i_pce_max_width;
+ int32_t i_lines = p_sys->ps_desk_planes[i_plane].i_pce_max_lines;
+ int32_t i_size_x_0 = p_sys->ps_desk_planes[0].i_pce_max_width;
+ int32_t i_size_y_0 = p_sys->ps_desk_planes[0].i_pce_max_lines;
+
+ float f_x_ratio = ((float) i_width) / ((float) i_size_x_0);
+ float f_y_ratio = ((float) i_lines) / ((float) i_size_y_0);
+
+ /* first: get min x and min y */
+ float f_min_curve_x, f_min_curve_y;
+ puzzle_get_min_bezier(&f_min_curve_x, &f_min_curve_y, f_x_ratio,
f_y_ratio, ps_pt, i_pts_nbr);
+
+ f_min_curve_y = __MIN(0,floor(f_min_curve_y));
+ f_min_curve_x = __MIN(0,floor(f_min_curve_x));
+
+ /* next: process each horizontal pixel lines */
+ int32_t i_min_y = (i_border==puzzle_SHAPE_TOP)?floor(f_min_curve_y):0;
+ int32_t i_nb_y = (i_border==puzzle_SHAPE_TOP)?(i_lines / 2 -
i_min_y):i_lines;
+
+ /* allocate memory */
+ ps_piece_shape->i_row_nbr = i_nb_y;
+ ps_piece_shape->i_first_row_offset = i_min_y;
+ ps_piece_shape->ps_piece_shape_row = malloc( sizeof(
piece_shape_row_t ) * ps_piece_shape->i_row_nbr );
+ if (!ps_piece_shape->ps_piece_shape_row)
+ return VLC_ENOMEM;
+
+ return puzzle_generate_shape_lines(p_filter, ps_piece_shape,
i_min_y, i_nb_y, f_x_ratio, f_y_ratio, ps_pt, i_pts_nbr, i_border, i_plane);
+}
+
+/*****************************************************************************
+ * when generating shape data: determine minimum bezier value
+
*****************************************************************************/
+void puzzle_get_min_bezier(float *f_min_curve_x, float *f_min_curve_y,
float f_x_ratio, float f_y_ratio, point_t *ps_pt, uint8_t i_pts_nbr)
+{
+ *f_min_curve_y = ps_pt[0].f_y * f_y_ratio;
+ *f_min_curve_x = ps_pt[0].f_x * f_x_ratio;
+
+ for (float f_t = 0; f_t <= i_pts_nbr - 1; f_t += 0.1 ) {
+ int8_t i_main_t = floor(f_t);
+ if ( i_main_t == i_pts_nbr - 1 )
+ i_main_t = i_pts_nbr - 2;
+ float f_sub_t = f_t - i_main_t;
+
+ *f_min_curve_x =
__MIN(*f_min_curve_x,bezier_val(ps_pt,f_sub_t,i_main_t,x) * f_x_ratio);
+ *f_min_curve_y =
__MIN(*f_min_curve_y,bezier_val(ps_pt,f_sub_t,i_main_t,y) * f_y_ratio);
+ }
+}
+
+/*****************************************************************************
+ * proceed with each line in order to generate data which will be used
+ * to draw each line of a piece sector
+
*****************************************************************************/
+int puzzle_generate_shape_lines( filter_t *p_filter, piece_shape_t
*ps_piece_shape, int32_t i_min_y, int32_t i_nb_y, float f_x_ratio, float
f_y_ratio, point_t *ps_pt, uint8_t i_pts_nbr, uint8_t i_border, uint8_t
i_plane)
+{
+ /* generate data required to draw a line of a piece sector */
+ for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++) {
+ int32_t i_row = i_y - i_min_y;
+
+ int32_t pi_sects[MAX_SECT];
+
+ uint8_t i_sect = puzzle_detect_curve( p_filter, i_y, f_x_ratio,
f_y_ratio, ps_pt, i_pts_nbr, i_border, i_plane, pi_sects);
+
+ /* ...we have to convert absolute values to offsets and take
into account min_curve_x */
+ int8_t i_s = 0;
+ int32_t i_last_x = (i_border==puzzle_SHAPE_TOP &&
(i_y>=0))?puzzle_diagonal_limit( p_filter, i_y, true, i_plane ):0;
+
+ for (i_s = 0; i_s<i_sect; i_s++) {
+ int32_t i_current_x = pi_sects[i_s];
+ int32_t i_delta = i_current_x - i_last_x;
+ pi_sects[i_s] = i_delta;
+
+ i_last_x = i_current_x;
+ }
+
+ switch (i_border)
+ {
+ case puzzle_SHAPE_TOP:
+ /* ...allocate memory and copy final values */
+ /* note for y > 0 we have to ignore the first offset as it
is included in "Left" piece shape */
+ if ( i_y >= 0 ) {
+ ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_sect);
+ if
(!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
+ for (uint8_t i=0; i<i_row;i++)
+ free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
+ free(ps_piece_shape->ps_piece_shape_row);
+ ps_piece_shape->ps_piece_shape_row = NULL;
+ return VLC_ENOMEM;
+ }
+ for (uint8_t i=0; i < i_sect; i++) {
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = i
% 2; /* 0 = fill ; 1 = offset */
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+ }
+ }
+ else {
+ ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_sect);
+ if
(!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
+ for (uint8_t i=0; i<i_row;i++)
+ free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
+ free(ps_piece_shape->ps_piece_shape_row);
+ ps_piece_shape->ps_piece_shape_row = NULL;
+ return VLC_ENOMEM;
+ }
+ for (uint8_t i=0; i < i_sect; i++) {
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type =
(i + 1) % 2; /* 0 = fill ; 1 = offset */
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+ }
+ }
+ break;
+ case puzzle_SHAPE_LEFT:
+ /* ...allocate memory and copy final values */
+ /* note for y > 0 we have to ignore the first offset as it
is included in "Left" piece shape */
+ ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_sect);
+ if
(!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
+ for (uint8_t i=0; i<i_row;i++)
+ free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
+ free(ps_piece_shape->ps_piece_shape_row);
+ ps_piece_shape->ps_piece_shape_row = NULL;
+ return VLC_ENOMEM;
+ }
+ for (uint8_t i=0; i < i_sect; i++) {
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type =
(i+1) % 2; /* 0 = fill ; 1 = offset */
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width =
pi_sects[i];
+ }
+ }
+ }
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * when generating shape data: detect all bezier curve intersections with
+ * current line
+
*****************************************************************************/
+int puzzle_detect_curve( filter_t *p_filter, int32_t i_y, float
f_x_ratio, float f_y_ratio, point_t *ps_pt, uint8_t i_pts_nbr, uint8_t
i_border, uint8_t i_plane, int32_t *pi_sects)
+{
+ int8_t i_main_t = 0;
+ float f_xd, f_yd;
+ float f_xo = ps_pt[0].f_x * f_x_ratio;
+ float f_yo = ps_pt[0].f_y * f_y_ratio;
+ int8_t i_sect = 0;
+
+ for (float f_t = 0; f_t <= i_pts_nbr - 1; f_t += 0.1 ) {
+ i_main_t = floor(f_t);
+ if ( i_main_t == i_pts_nbr - 1 )
+ i_main_t = i_pts_nbr - 2;
+ float f_sub_t = f_t - i_main_t;
+
+ f_xd = bezier_val(ps_pt,f_sub_t,i_main_t,x) * f_x_ratio;
+ f_yd = bezier_val(ps_pt,f_sub_t,i_main_t,y) * f_y_ratio;
+
+ if ((f_yo < (float)i_y+0.5 && f_yd >= (float)i_y+0.5) || (f_yo
> (float)i_y+0.5 && f_yd <= (float)i_y+0.5)) {
+ pi_sects[i_sect] = floor(((float)i_y+0.5 - f_yo) * (f_xd -
f_xo) / (f_yd - f_yo) + f_xo);
+ if (i_sect < MAX_SECT - 1)
+ i_sect++;
+ }
+
+ f_xo = f_xd;
+ f_yo = f_yd;
+ }
+ f_xd = ps_pt[i_pts_nbr - 1].f_x * f_x_ratio;
+ f_yd = ps_pt[i_pts_nbr - 1].f_y * f_y_ratio;
+
+ /* ...fill from this junction to next junction */
+ if ( i_y >= 0 ) {
+ /* last diagonal intersection */
+ pi_sects[i_sect] =
(i_border==puzzle_SHAPE_TOP)?puzzle_diagonal_limit( p_filter, i_y,
false, i_plane )
+ :puzzle_diagonal_limit( p_filter, i_y, true, i_plane );
+ if (i_sect < MAX_SECT - 1)
+ i_sect++;
+ }
+
+ /* ...reorder the list of intersection */
+ int32_t i_s = 0;
+
+ while (i_s < (i_sect - 1)) {
+ if (pi_sects[i_s] > pi_sects[i_s+1]) {
+ uint32_t i_temp = pi_sects[i_s];
+ pi_sects[i_s] = pi_sects[i_s+1];
+ pi_sects[i_s+1] = i_temp;
+ i_s = 0;
+ }
+ else {
+ i_s++;
+ }
+ }
+
+ return i_sect;
+}
+
+/*****************************************************************************
+ * generate Right shape data from Left shape data
+
*****************************************************************************/
+int puzzle_generate_sectLeft2Right( filter_t *p_filter, piece_shape_t
*ps_piece_shape, piece_shape_t *ps_left_piece_shape, uint8_t i_plane)
+{
+ if ((!ps_piece_shape) || (!ps_left_piece_shape))
+ return VLC_EGENERIC;
+
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ int32_t i_min_y = ps_left_piece_shape->i_first_row_offset;
+ int32_t i_nb_y = ps_left_piece_shape->i_row_nbr;
+
+ /* allocate memory */
+ ps_piece_shape->i_row_nbr = i_nb_y;
+ ps_piece_shape->i_first_row_offset = i_min_y;
+ ps_piece_shape->ps_piece_shape_row = malloc( sizeof(
piece_shape_row_t ) * i_nb_y );
+ if (!ps_piece_shape->ps_piece_shape_row)
+ return VLC_ENOMEM;
+
+ for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++) {
+ int32_t i_row = i_y - i_min_y;
+
+ int32_t i_width = p_sys->ps_desk_planes[i_plane].i_pce_max_width;
+ int32_t i_left_width = puzzle_diagonal_limit( p_filter, i_y,
true, i_plane );
+ int32_t i_right_width = i_width - puzzle_diagonal_limit(
p_filter, i_y, false, i_plane );
+ int16_t i_section_nbr =
ps_left_piece_shape->ps_piece_shape_row[i_row].i_section_nbr;
+
+ ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_section_nbr;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_section_nbr);
+ if (!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
+ for (uint8_t i=0; i<i_row;i++)
+ free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
+ free(ps_piece_shape->ps_piece_shape_row);
+ ps_piece_shape->ps_piece_shape_row = NULL;
+ return VLC_ENOMEM;
+ }
+
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_type =
+ ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_type;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_width =
+
ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_width
+ i_right_width - i_left_width;
+
+ for (int8_t i_s=0; i_s<i_section_nbr;i_s++) {
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_type =
+
ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_section_nbr
- 1 - i_s].i_type;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_width =
+
ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_section_nbr
- 1 - i_s].i_width
+ + (i_s == 0 ? i_right_width - i_left_width : 0);
+ }
+ }
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * generates Bottom shape data from Top shape data
+
*****************************************************************************/
+int puzzle_generate_sectTop2Btm( filter_t *p_filter, piece_shape_t
*ps_piece_shape, piece_shape_t *ps_top_piece_shape, uint8_t i_plane)
+{
+ if ((!ps_piece_shape) || (!ps_top_piece_shape))
+ return VLC_EGENERIC;
+
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ int32_t i_top_min_y = ps_top_piece_shape->i_first_row_offset;
+ int32_t i_top_nb_y = ps_top_piece_shape->i_row_nbr;
+ int32_t i_lines = p_sys->ps_desk_planes[i_plane].i_pce_max_lines;
+ int32_t i_max_y = p_sys->ps_desk_planes[i_plane].i_pce_max_lines -
i_top_min_y;
+
+ int32_t i_min_y = i_lines / 2;
+ int32_t i_nb_y = i_max_y - i_min_y;
+
+ /* allocate memory */
+ ps_piece_shape->i_row_nbr = i_nb_y;
+ ps_piece_shape->i_first_row_offset = i_min_y;
+ ps_piece_shape->ps_piece_shape_row = malloc( sizeof(
piece_shape_row_t ) * i_nb_y );
+ if (!ps_piece_shape->ps_piece_shape_row)
+ return VLC_ENOMEM;
+
+ for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++) {
+ int32_t i_top_y = 2 * i_min_y - i_y + (i_nb_y - i_top_nb_y);
+ int32_t i_row = i_y - i_min_y;
+ int32_t i_top_row = i_top_y - i_top_min_y;
+
+ if ( i_top_row < 0 || i_top_row >= i_top_nb_y ) { /* the line
does not exist in top */
+ ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = 1;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * 1);
+ if
(!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
+ for (uint8_t i=0; i<i_row;i++)
+ free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
+ free(ps_piece_shape->ps_piece_shape_row);
+ ps_piece_shape->ps_piece_shape_row = NULL;
+ return VLC_ENOMEM;
+ }
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_type = 0;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_width =
+ puzzle_diagonal_limit( p_filter, i_y, false, i_plane )
- 1 - (puzzle_diagonal_limit( p_filter, i_y, true, i_plane ) - 1);
+ }
+ else { /* copy the line from TopShape */
+ int32_t i_top_width =
+ puzzle_diagonal_limit( p_filter, i_top_y, false,
i_plane ) - 1 - (puzzle_diagonal_limit( p_filter, i_top_y, true, i_plane
) - 1);
+ int32_t i_width =
+ puzzle_diagonal_limit( p_filter, i_y, false, i_plane )
- 1 - (puzzle_diagonal_limit( p_filter, i_y, true, i_plane ) - 1);
+ int32_t i_left_adjust = ( i_width - i_top_width ) / 2;
+ int32_t i_right_adjust = ( i_width - i_top_width ) -
i_left_adjust;
+
+ int8_t i_section_nbr =
ps_top_piece_shape->ps_piece_shape_row[i_top_row].i_section_nbr;
+ ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_section_nbr;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc (
sizeof(row_section_t) * i_section_nbr);
+ if
(!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
+ for (uint8_t i=0; i<i_row;i++)
+ free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
+ free(ps_piece_shape->ps_piece_shape_row);
+ ps_piece_shape->ps_piece_shape_row = NULL;
+ return VLC_ENOMEM;
+ }
+
+ for (int8_t i_s=0; i_s<i_section_nbr; i_s++) {
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_type =
+
ps_top_piece_shape->ps_piece_shape_row[i_top_row].ps_row_section[i_s].i_type;
+ ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_width =
+
ps_top_piece_shape->ps_piece_shape_row[i_top_row].ps_row_section[i_s].i_width
+ + (i_s == 0 ? i_left_adjust : (i_s ==
i_section_nbr-1 ? i_right_adjust : 0));
+ }
+ }
+ }
+ return VLC_SUCCESS;
+}
diff --git a/modules/video_filter/puzzle_pce.h
b/modules/video_filter/puzzle_pce.h
new file mode 100644
index 0000000..e9db183
--- /dev/null
+++ b/modules/video_filter/puzzle_pce.h
@@ -0,0 +1,112 @@
+/*****************************************************************************
+ * puzzle_pce.h : Puzzle game filter - pieces functions
+
*****************************************************************************
+ * Copyright (C) 2013 Vianney Boyer
+ * $Id$
+ *
+ * Author: Vianney Boyer <vlcvboyer -at- gmail -dot- com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+
*****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+
*****************************************************************************/
+#ifndef VLC_LIB_PUZZLE_PCE_H
+#define VLC_LIB_PUZZLE_PCE_H 1
+
+#include <vlc_common.h>
+#include <vlc_filter.h>
+
+#include "puzzle_bezier.h"
+#include "puzzle_lib.h"
+
+#define SHAPES_QTY 20
+#define PIECE_TYPE_NBR (4*2*(1+SHAPES_QTY))
+
+#define puzzle_SHAPE_TOP 1
+#define puzzle_SHAPE_LEFT 2
+#define puzzle_SHAPE_RIGHT 4
+#define puzzle_SHAPE_BTM 8
+
+/*****************************************************************************
+ * Local prototypes
+
*****************************************************************************/
+
+typedef struct {
+ uint8_t i_type; /* 0 = fill ; 1 = offset */
+ int32_t i_width;
+} row_section_t;
+
+typedef struct {
+ int32_t i_section_nbr;
+ row_section_t *ps_row_section;
+} piece_shape_row_t;
+
+typedef struct {
+ int32_t i_row_nbr;
+ int32_t i_first_row_offset;
+ piece_shape_row_t *ps_piece_shape_row;
+} piece_shape_t;
+
+typedef struct {
+ int32_t i_original_x, i_original_y;
+ int32_t i_actual_x, i_actual_y;
+ int32_t i_width, i_lines;
+} piece_in_plane_t;
+
+typedef struct {
+ int32_t i_original_row, i_original_col;
+
+ int32_t i_top_shape, i_btm_shape, i_right_shape, i_left_shape;
+
+ piece_in_plane_t *ps_piece_in_plane;
+
+ bool b_finished;
+ bool b_overlap;
+
+ int8_t i_actual_angle; /* 0 = 0°, 1 = 90°...
rotation center = top-left corner */
+ int32_t i_actual_mirror; /* +1 = without mirror ;
-1 = with mirror */
+ int32_t i_step_x_x, i_step_x_y, i_step_y_y, i_step_y_x;
+ int32_t i_ORx, i_OTy, i_OLx, i_OBy; /* location of original
piece's edges */
+ int32_t i_TLx, i_TLy, i_TRx, i_TRy, i_BLx, i_BLy, i_BRx, i_BRy; /*
location of grabed piece's corners */
+ int32_t i_max_x, i_min_x, i_max_y, i_min_y, i_center_x, i_center_y;
+
+ uint32_t i_group_ID;
+} piece_t;
+
+int puzzle_bake_pieces_shapes ( filter_t * );
+void puzzle_free_ps_pieces_shapes ( filter_t * );
+
+int puzzle_find_piece( filter_t *p_filter, int32_t i_x, int32_t i_y,
int32_t i_except);
+void puzzle_calculate_corners( filter_t *, int32_t i_piece );
+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 );
+void puzzle_move_group( filter_t *p_filter, int32_t i_piece, int32_t
i_dx, int32_t i_dy);
+
+void puzzle_drw_basic_pce_in_plane( filter_t *p_filter, picture_t
*p_pic_in, picture_t *p_pic_out, uint8_t i_plane, piece_t *ps_piece);
+void puzzle_drw_adv_pce_in_plane( filter_t *p_filter, picture_t
*p_pic_in, picture_t *p_pic_out, uint8_t i_plane, piece_t *ps_piece);
+void puzzle_drw_complex_pce_in_plane( filter_t *p_filter, picture_t
*p_pic_in, picture_t *p_pic_out, uint8_t i_plane, piece_t *ps_piece,
uint32_t i_pce);
+void puzzle_draw_pieces( filter_t *p_filter, picture_t *p_pic_in,
picture_t *p_pic_out);
+int32_t puzzle_diagonal_limit( filter_t *p_filter, int32_t i_y, bool
b_left, uint8_t i_plane );
+
+int puzzle_generate_sect_border( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_plane, uint8_t i_border);
+int puzzle_generate_sect_bezier( filter_t *p_filter, piece_shape_t
*ps_piece_shape, uint8_t i_pts_nbr, point_t *ps_pt, uint8_t i_plane,
uint8_t i_border);
+void puzzle_get_min_bezier(float *f_min_curve_x, float *f_min_curve_y,
float f_x_ratio, float f_y_ratio, point_t *ps_pt, uint8_t i_pts_nbr);
+int puzzle_generate_shape_lines( filter_t *p_filter, piece_shape_t
*ps_piece_shape, int32_t i_min_y, int32_t i_nb_y, float f_x_ratio, float
f_y_ratio, point_t *ps_pt, uint8_t i_pts_nbr, uint8_t i_border, uint8_t
i_plane);
+int puzzle_detect_curve( filter_t *p_filter, int32_t i_y, float
f_x_ratio, float f_y_ratio, point_t *ps_pt, uint8_t i_pts_nbr, uint8_t
i_border, uint8_t i_plane, int32_t *pi_sects);
+int puzzle_generate_sectLeft2Right( filter_t *p_filter, piece_shape_t
*ps_piece_shape, piece_shape_t *ps_left_piece_shape, uint8_t i_plane);
+int puzzle_generate_sectTop2Btm( filter_t *p_filter, piece_shape_t
*ps_piece_shape, piece_shape_t *ps_top_piece_shape, uint8_t i_plane);
+
+#endif
--
1.7.9.5
Le 15/04/2013 17:51, Denis Charmet a écrit :
> Le lundi 15 avril 2013 à 02:15:36, Vianney Boyer a écrit :
>> +int puzzle_bake_pieces_shapes( filter_t *p_filter)
>> +{
> [...]
>> + if (i_ret != VLC_SUCCESS) return i_ret;
>> + i_ret = puzzle_generate_sectLeft2Right( p_filter,
>> &p_sys->ps_pieces_shapes[i_currect_shape+7][i_plane],
>> &p_sys->ps_pieces_shapes[i_currect_shape+1][i_plane], i_plane);
>> + if (i_ret != VLC_SUCCESS) return i_ret;
>> + }
>> +
>> + free(ps_scale_pts_H);
>> + free(ps_scale_pts_V);
>> + free(ps_neg_pts_H);
>> + free(ps_neg_pts_V);
> Those are leaked in all your error cases.
>
>> +/*****************************************************************************
>> + * generate data which will be used to draw each line of a piece
>> sector based
>> + * on bezier curve
>> + *****************************************************************************/
>> +int puzzle_generate_sect_bezier( filter_t *p_filter, piece_shape_t
>> *ps_piece_shape, uint8_t i_pts_nbr, point_t *ps_pt, uint8_t i_plane,
>> uint8_t i_border)
>> +{
> [...]
>> +
>> + int i_ret = puzzle_generate_shape_lines(p_filter,
>> ps_piece_shape, i_min_y, i_nb_y, f_x_ratio, f_y_ratio, ps_pt,
>> i_pts_nbr, i_border, i_plane);
>> + if (i_ret != VLC_SUCCESS)
>> + return i_ret;
> why this if? just return i_ret. (Maybe found in other functions)
>> +
>> + return VLC_SUCCESS;
>> +}
>> +
> [...]
>> + ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc
>> ( sizeof(row_section_t) * i_sect);
>> + if
>> (!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
>> + for (uint8_t i=0; i<i_row;i++)
>> + free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
>> + free(ps_piece_shape->ps_piece_shape_row);
>> + return VLC_ENOMEM;
>> + }
> I don't have the time right now to check but I suppose that
> (ps_piece_shape->ps_piece_shape_row should be freed in another function,
> shouldn't it be set to NULL to avoid potential double free?
>
> Regards,
>
More information about the vlc-devel
mailing list