Vout: move the AndroidSurface vout to a subdirectory
[vlc.git] / modules / video_filter / puzzle_pce.c
blobd11cecbc4f95780d139c51452438aafbadbea4f5
1 /*****************************************************************************
2 * puzzle_pce.c : Puzzle game filter - pieces functions
3 *****************************************************************************
4 * Copyright (C) 2013 Vianney Boyer
5 * $Id$
7 * Author: Vianney Boyer <vlcvboyer -at- gmail -dot- com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31 #include <math.h>
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35 #include <vlc_filter.h>
36 #include <vlc_rand.h>
38 #include "filter_picture.h"
40 #include "puzzle_bezier.h"
41 #include "puzzle_lib.h"
42 #include "puzzle_pce.h"
44 #define SHAPES_QTY 20
45 #define PIECE_TYPE_NBR (4*2*(1+SHAPES_QTY))
47 /*****************************************************************************
48 * puzzle_bake_pieces_shapes: allocate and compute shapes
49 *****************************************************************************/
50 int puzzle_bake_pieces_shapes( filter_t *p_filter)
52 /* note:
53 * piece_shape_t **ps_pieces_shapes; * array [each piece type (PCE_TYPE_NBR * 4 ( * negative ): top, left,right,btm)][each plane] of piece definition
54 * 0 => left border
55 * 1 => left border (negative, never used)
56 * 2 => top border
57 * .....
58 * 8 => bezier left
59 * 9 => bezier left negative
60 * 10 => bezier top
61 * 11 => bezier top negative
62 * 12 => bezier btm
63 * 13 => bezier btm negative
64 * 14 => bezier right
65 * 15 => bezier right negative
66 * .....
69 filter_sys_t *p_sys = p_filter->p_sys;
71 puzzle_free_ps_pieces_shapes(p_filter);
72 p_sys->ps_pieces_shapes = malloc( sizeof( piece_shape_t *) * PIECE_TYPE_NBR );
73 if( !p_sys->ps_pieces_shapes )
74 return VLC_ENOMEM;
76 for (int32_t i_piece = 0; i_piece < PIECE_TYPE_NBR; i_piece++) {
77 p_sys->ps_pieces_shapes[i_piece] = malloc( sizeof( piece_shape_t) * p_sys->s_allocated.i_planes );
78 if( !p_sys->ps_pieces_shapes[i_piece] )
79 return VLC_ENOMEM;
80 for (uint8_t i_plane = 0; i_plane < p_filter->p_sys->s_allocated.i_planes; i_plane++) {
81 p_sys->ps_pieces_shapes[i_piece][i_plane].i_row_nbr = 0;
82 p_sys->ps_pieces_shapes[i_piece][i_plane].ps_piece_shape_row = NULL;
86 int32_t i_currect_shape = 0;
88 for (uint8_t i_plane = 0; i_plane < p_filter->p_sys->s_allocated.i_planes; i_plane++) {
89 int i_ret;
90 i_ret = puzzle_generate_sect_border( p_filter, &p_sys->ps_pieces_shapes[i_currect_shape+0][i_plane], i_plane, puzzle_SHAPE_LEFT);
91 if (i_ret != VLC_SUCCESS) return i_ret;
92 i_ret = puzzle_generate_sect_border( p_filter, &p_sys->ps_pieces_shapes[i_currect_shape+1][i_plane], i_plane, puzzle_SHAPE_LEFT);
93 if (i_ret != VLC_SUCCESS) return i_ret;
94 i_ret = puzzle_generate_sect_border( p_filter, &p_sys->ps_pieces_shapes[i_currect_shape+2][i_plane], i_plane, puzzle_SHAPE_TOP);
95 if (i_ret != VLC_SUCCESS) return i_ret;
96 i_ret = puzzle_generate_sect_border( p_filter, &p_sys->ps_pieces_shapes[i_currect_shape+3][i_plane], i_plane, puzzle_SHAPE_TOP);
97 if (i_ret != VLC_SUCCESS) return i_ret;
98 i_ret = puzzle_generate_sect_border( p_filter, &p_sys->ps_pieces_shapes[i_currect_shape+4][i_plane], i_plane, puzzle_SHAPE_BTM);
99 if (i_ret != VLC_SUCCESS) return i_ret;
100 i_ret = puzzle_generate_sect_border( p_filter, &p_sys->ps_pieces_shapes[i_currect_shape+5][i_plane], i_plane, puzzle_SHAPE_BTM);
101 if (i_ret != VLC_SUCCESS) return i_ret;
102 i_ret = puzzle_generate_sect_border( p_filter, &p_sys->ps_pieces_shapes[i_currect_shape+6][i_plane], i_plane, puzzle_SHAPE_RIGHT);
103 if (i_ret != VLC_SUCCESS) return i_ret;
104 i_ret = puzzle_generate_sect_border( p_filter, &p_sys->ps_pieces_shapes[i_currect_shape+7][i_plane], i_plane, puzzle_SHAPE_RIGHT);
105 if (i_ret != VLC_SUCCESS) return i_ret;
108 i_currect_shape += 8;
110 int32_t i_width = p_sys->ps_desk_planes[0].i_pce_max_width;
111 int32_t i_lines = p_sys->ps_desk_planes[0].i_pce_max_lines;
113 for (int32_t i_shape = 0; i_shape<SHAPES_QTY; i_shape++) {
115 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);
116 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);
117 point_t *ps_neg_pts_H = puzzle_curve_H_2_negative(7, ps_scale_pts_H);
118 point_t *ps_neg_pts_V = puzzle_curve_V_2_negative(7, ps_scale_pts_V);
120 if (!ps_scale_pts_H || !ps_scale_pts_V || !ps_neg_pts_H || !ps_neg_pts_V) {
121 free(ps_scale_pts_H);
122 free(ps_scale_pts_V);
123 free(ps_neg_pts_H);
124 free(ps_neg_pts_V);
125 return VLC_EGENERIC;
128 int i_ret;
129 for (uint8_t i_plane = 0; i_plane < p_filter->p_sys->s_allocated.i_planes; i_plane++) {
130 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);
131 if (i_ret != VLC_SUCCESS) break;
132 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);
133 if (i_ret != VLC_SUCCESS) break;
134 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);
135 if (i_ret != VLC_SUCCESS) break;
136 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);
137 if (i_ret != VLC_SUCCESS) break;
139 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);
140 if (i_ret != VLC_SUCCESS) break;
141 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);
142 if (i_ret != VLC_SUCCESS) break;
143 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);
144 if (i_ret != VLC_SUCCESS) break;
145 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);
146 if (i_ret != VLC_SUCCESS) break;
149 free(ps_scale_pts_H);
150 free(ps_scale_pts_V);
151 free(ps_neg_pts_H);
152 free(ps_neg_pts_V);
154 if (i_ret != VLC_SUCCESS) return i_ret;
156 i_currect_shape += 8;
159 p_sys->b_shape_init = true;
161 return VLC_SUCCESS;
164 /* free allocated shapes data */
165 void puzzle_free_ps_pieces_shapes( filter_t *p_filter)
167 filter_sys_t *p_sys = p_filter->p_sys;
169 if (p_sys->ps_pieces_shapes == NULL)
170 return;
172 for (int32_t p = 0; p < p_sys->s_allocated.i_piece_types; p++) {
173 for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) {
174 for (int32_t r = 0; r < p_sys->ps_pieces_shapes[p][i_plane].i_row_nbr; r++)
175 free( p_sys->ps_pieces_shapes[p][i_plane].ps_piece_shape_row[r].ps_row_section );
176 free( p_sys->ps_pieces_shapes[p][i_plane].ps_piece_shape_row );
178 free( p_sys->ps_pieces_shapes[p] );
180 free( p_sys->ps_pieces_shapes );
181 p_sys->ps_pieces_shapes = NULL;
184 /*****************************************************************************
185 * puzzle_find_piece: use piece corners to find the piece selected
186 * by mouse cursor
187 *****************************************************************************/
188 int puzzle_find_piece( filter_t *p_filter, int32_t i_x, int32_t i_y, int32_t i_except) {
189 filter_sys_t *p_sys = p_filter->p_sys;
191 for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
192 piece_t *ps_current_piece = &p_sys->ps_pieces[i];
193 if (( ps_current_piece->i_min_x <= i_x ) &&
194 ( ps_current_piece->i_max_x >= i_x ) &&
195 ( ps_current_piece->i_min_y <= i_y ) &&
196 ( ps_current_piece->i_max_y >= i_y ) &&
197 ( (int32_t)i != i_except ) )
199 return i;
202 return -1;
205 /*****************************************************************************
206 * puzzle_calculate_corners: calculate corners location & regen geometry data
207 *****************************************************************************/
208 void puzzle_calculate_corners( filter_t *p_filter, int32_t i_piece )
210 filter_sys_t *p_sys = p_filter->p_sys;
211 piece_t *ps_piece = &p_sys->ps_pieces[i_piece];
213 switch ( ps_piece->i_actual_angle)
215 case 0:
216 ps_piece->i_step_x_x = ps_piece->i_actual_mirror;
217 ps_piece->i_step_x_y = 0;
218 ps_piece->i_step_y_y = 1;
219 ps_piece->i_step_y_x = 0;
220 break;
221 case 1:
222 ps_piece->i_step_x_x = 0;
223 ps_piece->i_step_x_y = -ps_piece->i_actual_mirror; /* x offset on original pict creates negative y offset on desk */
224 ps_piece->i_step_y_y = 0;
225 ps_piece->i_step_y_x = 1;
226 break;
227 case 2:
228 ps_piece->i_step_x_x = -ps_piece->i_actual_mirror;
229 ps_piece->i_step_x_y = 0;
230 ps_piece->i_step_y_y = -1;
231 ps_piece->i_step_y_x = 0;
232 break;
233 case 3:
234 ps_piece->i_step_x_x = 0;
235 ps_piece->i_step_x_y = ps_piece->i_actual_mirror;
236 ps_piece->i_step_y_y = 0;
237 ps_piece->i_step_y_x = -1;
238 break;
241 /* regen geometry */
242 for (uint8_t i_plane = 1; i_plane < p_sys->s_allocated.i_planes; i_plane++) {
243 ps_piece->ps_piece_in_plane[i_plane].i_actual_x =
244 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;
245 ps_piece->ps_piece_in_plane[i_plane].i_actual_y =
246 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;
249 /* regen location of grabed piece's corners */
250 int32_t i_width = ps_piece->ps_piece_in_plane[0].i_width;
251 int32_t i_lines = ps_piece->ps_piece_in_plane[0].i_lines;
253 ps_piece->i_TLx = ps_piece->ps_piece_in_plane[0].i_actual_x;
254 ps_piece->i_TLy = ps_piece->ps_piece_in_plane[0].i_actual_y;
255 ps_piece->i_TRx = ps_piece->i_TLx + ( i_width - 1 ) * ps_piece->i_step_x_x;
256 ps_piece->i_TRy = ps_piece->i_TLy + ( i_width - 1 ) * ps_piece->i_step_x_y;
257 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;
258 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;
259 ps_piece->i_BLx = ps_piece->i_TLx + ( i_lines - 1 ) * ps_piece->i_step_y_x;
260 ps_piece->i_BLy = ps_piece->i_TLy + ( i_lines - 1 ) * ps_piece->i_step_y_y;
262 ps_piece->i_max_x = __MAX( __MAX( ps_piece->i_TLx, ps_piece->i_TRx ), __MAX( ps_piece->i_BLx, ps_piece->i_BRx ) );
263 ps_piece->i_min_x = __MIN( __MIN( ps_piece->i_TLx, ps_piece->i_TRx ), __MIN( ps_piece->i_BLx, ps_piece->i_BRx ) );
264 ps_piece->i_max_y = __MAX( __MAX( ps_piece->i_TLy, ps_piece->i_TRy ), __MAX( ps_piece->i_BLy, ps_piece->i_BRy ) );
265 ps_piece->i_min_y = __MIN( __MIN( ps_piece->i_TLy, ps_piece->i_TRy ), __MIN( ps_piece->i_BLy, ps_piece->i_BRy ) );
267 ps_piece->i_center_x = ( ps_piece->i_max_x + ps_piece->i_min_x ) / 2;
268 ps_piece->i_center_y = ( ps_piece->i_max_y + ps_piece->i_min_y ) / 2;
270 int32_t pce_overlap = puzzle_find_piece( p_filter, ps_piece->i_center_x, ps_piece->i_center_y, i_piece);
272 if ( ( pce_overlap != NO_PCE ) && ( p_sys->pi_group_qty[ps_piece->i_group_ID] == 1 ) )
273 ps_piece->b_overlap = true;
276 /*****************************************************************************
277 * rotate piece when user click on mouse
278 *****************************************************************************/
279 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 )
281 filter_sys_t *p_sys = p_filter->p_sys;
282 piece_t *ps_piece = &p_sys->ps_pieces[i_piece];
284 if ( p_sys->s_current_param.i_rotate == 0 )
285 return;
287 if ( p_sys->s_current_param.i_rotate == 1 && (i_rotate_mirror != 2) )
288 return;
290 for ( uint8_t i=0; i < abs( i_rotate_mirror ); i++) {
291 int32_t i_tempx, i_tempy;
293 /* piece has to be rotated by 90° */
294 if ( i_rotate_mirror > 0 ) {
295 ps_piece->i_actual_angle++;
296 ps_piece->i_actual_angle &= 0x03;
298 i_tempx = -( i_center_y - ps_piece->ps_piece_in_plane[0].i_actual_y ) + i_center_x;
299 i_tempy = +( i_center_x - ps_piece->ps_piece_in_plane[0].i_actual_x ) + i_center_y;
301 else {
302 ps_piece->i_actual_angle--;
303 ps_piece->i_actual_angle &= 0x03;
305 i_tempx = +( i_center_y - ps_piece->ps_piece_in_plane[0].i_actual_y ) + i_center_x;
306 i_tempy = -( i_center_x - ps_piece->ps_piece_in_plane[0].i_actual_x ) + i_center_y;
309 ps_piece->ps_piece_in_plane[0].i_actual_x = i_tempx;
310 ps_piece->ps_piece_in_plane[0].i_actual_y = i_tempy;
312 if ( ps_piece->i_actual_angle == 0 && p_sys->s_current_param.i_rotate == 3 && !b_avoid_mirror ) {
313 ps_piece->ps_piece_in_plane[0].i_actual_x = 2 * i_center_x - ps_piece->ps_piece_in_plane[0].i_actual_x;
314 ps_piece->i_actual_mirror *= -1;
316 puzzle_calculate_corners( p_filter, i_piece );
320 /*****************************************************************************
321 * move group of joined pieces when user drag'n drop it with mouse
322 *****************************************************************************/
323 void puzzle_move_group( filter_t *p_filter, int32_t i_piece, int32_t i_dx, int32_t i_dy)
325 filter_sys_t *p_sys = p_filter->p_sys;
326 uint32_t i_group_ID = p_sys->ps_pieces[i_piece].i_group_ID;
327 for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) {
328 piece_t *ps_piece = &p_sys->ps_pieces[i];
329 if (ps_piece->i_group_ID == i_group_ID) {
330 ps_piece->b_finished = false;
331 ps_piece->ps_piece_in_plane[0].i_actual_x += i_dx;
332 ps_piece->ps_piece_in_plane[0].i_actual_y += i_dy;
334 puzzle_calculate_corners( p_filter, i );
339 /*****************************************************************************
340 * draw straight rectangular piece in the specified plane
341 *****************************************************************************/
342 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)
344 /* basic version rectangular & angle = 0 */
345 filter_sys_t *p_sys = p_filter->p_sys;
347 if ((p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL) || (ps_piece == NULL))
348 return;
350 const int32_t i_src_pitch = p_pic_in->p[i_plane].i_pitch;
351 const int32_t i_dst_pitch = p_pic_out->p[i_plane].i_pitch;
352 const int32_t i_src_width = p_pic_in->p[i_plane].i_pitch / p_pic_in->p[i_plane].i_pixel_pitch;
353 const int32_t i_dst_width = p_pic_out->p[i_plane].i_pitch / p_pic_out->p[i_plane].i_pixel_pitch;
354 const int32_t i_pixel_pitch = p_pic_out->p[i_plane].i_pixel_pitch;
355 const int32_t i_src_visible_lines = p_pic_in->p[i_plane].i_visible_lines;
356 const int32_t i_dst_visible_lines = p_pic_out->p[i_plane].i_visible_lines;
357 uint8_t *p_src = p_pic_in->p[i_plane].p_pixels;
358 uint8_t *p_dst = p_pic_out->p[i_plane].p_pixels;
360 const int32_t i_desk_start_x = ps_piece->ps_piece_in_plane[i_plane].i_actual_x;
361 const int32_t i_desk_start_y = ps_piece->ps_piece_in_plane[i_plane].i_actual_y;
362 const int32_t i_pic_start_x = ps_piece->ps_piece_in_plane[i_plane].i_original_x;
363 const int32_t i_pic_start_y = ps_piece->ps_piece_in_plane[i_plane].i_original_y;
364 const int32_t i_width = ps_piece->ps_piece_in_plane[i_plane].i_width;
365 const int32_t i_lines = ps_piece->ps_piece_in_plane[i_plane].i_lines;
367 const int32_t i_ofs_x = __MAX(0, __MAX(-i_desk_start_x,-i_pic_start_x));
368 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 ));
369 const int32_t i_ofs_y = __MAX(0, __MAX(-i_desk_start_y,-i_pic_start_y));
370 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 ));
372 for (int32_t i_y = i_ofs_y; i_y < i_count_y; i_y++) {
373 memcpy( p_dst + (i_desk_start_y + i_y) * i_dst_pitch + ( i_desk_start_x + i_ofs_x ) * i_pixel_pitch,
374 p_src + (i_pic_start_y + i_y) * i_src_pitch + ( i_pic_start_x + i_ofs_x ) * i_pixel_pitch,
375 ( i_count_x - i_ofs_x ) * i_pixel_pitch );
378 return;
381 /*****************************************************************************
382 * draw oriented rectangular piece in the specified plane
383 *****************************************************************************/
384 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)
386 /* here we still have rectangular shape but angle is not 0 */
387 filter_sys_t *p_sys = p_filter->p_sys;
389 if ((p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL) || (ps_piece == NULL))
390 return;
392 const int32_t i_src_pitch = p_pic_in->p[i_plane].i_pitch;
393 const int32_t i_dst_pitch = p_pic_out->p[i_plane].i_pitch;
394 const int32_t i_src_width = p_pic_in->p[i_plane].i_pitch / p_pic_in->p[i_plane].i_pixel_pitch;
395 const int32_t i_dst_width = p_pic_out->p[i_plane].i_pitch / p_pic_out->p[i_plane].i_pixel_pitch;
396 const int32_t i_pixel_pitch = p_pic_out->p[i_plane].i_pixel_pitch;
397 const int32_t i_src_visible_lines = p_pic_in->p[i_plane].i_visible_lines;
398 const int32_t i_dst_visible_lines = p_pic_out->p[i_plane].i_visible_lines;
399 uint8_t *p_src = p_pic_in->p[i_plane].p_pixels;
400 uint8_t *p_dst = p_pic_out->p[i_plane].p_pixels;
402 const int32_t i_desk_start_x = ps_piece->ps_piece_in_plane[i_plane].i_actual_x;
403 const int32_t i_desk_start_y = ps_piece->ps_piece_in_plane[i_plane].i_actual_y;
404 const int32_t i_pic_start_x = ps_piece->ps_piece_in_plane[i_plane].i_original_x;
405 const int32_t i_pic_start_y = ps_piece->ps_piece_in_plane[i_plane].i_original_y;
406 const int32_t i_width = ps_piece->ps_piece_in_plane[i_plane].i_width;
407 const int32_t i_lines = ps_piece->ps_piece_in_plane[i_plane].i_lines;
409 for (int32_t i_y = 0; i_y < i_lines; i_y++) {
410 int32_t i_current_src_y = i_pic_start_y + i_y;
412 if ( ( i_current_src_y >= 0 ) && ( i_current_src_y < i_src_visible_lines ) ) {
413 for (int32_t i_x = 0; i_x < i_width; i_x++) {
414 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;
415 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;
416 int32_t i_current_src_x = i_pic_start_x + i_x;
418 if ( ( i_current_dst_x >= 0 ) && ( i_current_src_x >= 0 )
419 && ( i_current_dst_x < i_dst_width ) && ( i_current_src_x < i_src_width )
420 && ( i_current_dst_y >= 0 ) && ( i_current_dst_y < i_dst_visible_lines ) )
422 memcpy( p_dst + i_current_dst_y * i_dst_pitch + i_current_dst_x * i_pixel_pitch,
423 p_src + i_current_src_y * i_src_pitch + i_current_src_x * i_pixel_pitch,
424 i_pixel_pitch );
430 return;
433 /*****************************************************************************
434 * draw complex shape in the specified plane
435 *****************************************************************************/
436 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)
438 /* "puzzle" shape and maybe angle != 0 */
439 filter_sys_t *p_sys = p_filter->p_sys;
441 if ((p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL) || (ps_piece == NULL))
442 return;
444 const int32_t i_src_pitch = p_pic_in->p[i_plane].i_pitch;
445 const int32_t i_dst_pitch = p_pic_out->p[i_plane].i_pitch;
446 const int32_t i_src_width = p_pic_in->p[i_plane].i_pitch / p_pic_in->p[i_plane].i_pixel_pitch;
447 const int32_t i_dst_width = p_pic_out->p[i_plane].i_pitch / p_pic_out->p[i_plane].i_pixel_pitch;
448 const int32_t i_pixel_pitch = p_pic_out->p[i_plane].i_pixel_pitch;
449 const int32_t i_src_visible_lines = p_pic_in->p[i_plane].i_visible_lines;
450 const int32_t i_dst_visible_lines = p_pic_out->p[i_plane].i_visible_lines;
451 uint8_t *p_src = p_pic_in->p[i_plane].p_pixels;
452 uint8_t *p_dst = p_pic_out->p[i_plane].p_pixels;
454 const int32_t i_desk_start_x = ps_piece->ps_piece_in_plane[i_plane].i_actual_x;
455 const int32_t i_desk_start_y = ps_piece->ps_piece_in_plane[i_plane].i_actual_y;
456 const int32_t i_pic_start_x = ps_piece->ps_piece_in_plane[i_plane].i_original_x;
457 const int32_t i_pic_start_y = ps_piece->ps_piece_in_plane[i_plane].i_original_y;
459 piece_shape_t *ps_top_shape = &p_sys->ps_pieces_shapes[ps_piece->i_top_shape][i_plane];
460 piece_shape_t *ps_btm_shape = &p_sys->ps_pieces_shapes[ps_piece->i_btm_shape][i_plane];
461 piece_shape_t *ps_right_shape = &p_sys->ps_pieces_shapes[ps_piece->i_right_shape][i_plane];
462 piece_shape_t *ps_left_shape = &p_sys->ps_pieces_shapes[ps_piece->i_left_shape][i_plane];
463 piece_shape_t *ps_shape;
465 int32_t i_min_y = ps_top_shape->i_first_row_offset;
466 int32_t i_max_y = ps_btm_shape->i_first_row_offset + ps_btm_shape->i_row_nbr - 1;
468 for (int32_t i_y = i_min_y; i_y <= i_max_y; i_y++) {
469 int32_t i_current_src_y = i_pic_start_y + i_y;
471 if ( ( i_current_src_y >= 0 ) && ( i_current_src_y < i_src_visible_lines ) ) {
472 int32_t i_sect_start_x = 0;
474 /* process each sub shape (each quarter) */
475 for (int8_t i_shape=0; i_shape < 4; i_shape++) {
476 switch ( i_shape )
478 case 0:
479 ps_shape = ps_left_shape;
480 break;
481 case 1:
482 ps_shape = ps_top_shape;
483 break;
484 case 2:
485 ps_shape = ps_btm_shape;
486 break;
487 case 3:
488 ps_shape = ps_right_shape;
489 break;
492 int32_t i_r = i_y - ps_shape->i_first_row_offset;
494 if (i_r <0 || i_r >= ps_shape->i_row_nbr)
495 continue;
497 piece_shape_row_t *ps_piece_shape_row = &ps_shape->ps_piece_shape_row[i_r];
499 for (int32_t i_s = 0; i_s < ps_piece_shape_row->i_section_nbr; i_s++) {
500 uint8_t i_type = ps_piece_shape_row->ps_row_section[i_s].i_type;
501 int32_t i_width = ps_piece_shape_row->ps_row_section[i_s].i_width;
502 if (i_type == 0) {
503 /* copy pixel line from input image to puzzle desk */
504 for (int32_t i_x = 0; i_x < i_width; i_x++) {
505 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;
506 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;
507 int32_t i_current_src_x = i_pic_start_x + (i_sect_start_x + i_x);
509 if ( i_current_dst_x < 0 || i_current_dst_x >= i_dst_width
510 || i_current_src_x < 0 || i_current_src_x >= i_src_width
511 || i_current_dst_y < 0 || i_current_dst_y >= i_dst_visible_lines )
512 continue;
514 memcpy( p_dst + i_current_dst_y * i_dst_pitch + i_current_dst_x * i_pixel_pitch,
515 p_src + i_current_src_y * i_src_pitch + i_current_src_x * i_pixel_pitch,
516 i_pixel_pitch );
518 /* Check if mouse pointer is over this pixel
519 * Yes: set i_pointed_pce = current drawn piece
521 if ((i_plane == 0) && (p_sys->i_mouse_x == i_current_dst_x )
522 && (p_sys->i_mouse_y == i_current_dst_y ))
523 p_sys->i_pointed_pce = i_pce;
526 i_sect_start_x += i_width;
532 return;
535 /*****************************************************************************
536 * draw all puzzle pieces on the desk
537 *****************************************************************************/
538 void puzzle_draw_pieces( filter_t *p_filter, picture_t *p_pic_in, picture_t *p_pic_out)
540 filter_sys_t *p_sys = p_filter->p_sys;
542 if ((p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL))
543 return;
545 for( uint8_t i_plane = 0; i_plane < p_pic_out->i_planes; i_plane++ ) {
546 for ( int32_t i = p_sys->s_allocated.i_pieces_nbr-1; i >= 0 ; i-- ) {
547 piece_t *ps_piece = &p_sys->ps_pieces[i];
549 if (!p_sys->s_current_param.b_advanced
550 || (ps_piece->i_actual_mirror == 1 && ps_piece->i_actual_angle == 0
551 && p_sys->s_current_param.i_shape_size == 0))
553 puzzle_drw_basic_pce_in_plane(p_filter, p_pic_in, p_pic_out, i_plane, ps_piece);
555 else if ( ( p_sys->s_current_param.i_shape_size == 0) || !p_sys->b_shape_init
556 || (p_sys->ps_pieces_shapes == NULL) || (!p_sys->b_shape_init) )
558 puzzle_drw_adv_pce_in_plane(p_filter, p_pic_in, p_pic_out, i_plane, ps_piece);
560 else {
561 puzzle_drw_complex_pce_in_plane(p_filter, p_pic_in, p_pic_out, i_plane, ps_piece, i);
566 return;
569 /*****************************************************************************
570 * when generating shape data: determine limit between sectors to be drawn
571 *****************************************************************************/
572 int32_t puzzle_diagonal_limit( filter_t *p_filter, int32_t i_y, bool b_left, uint8_t i_plane )
574 filter_sys_t *p_sys = p_filter->p_sys;
576 if (b_left ^ (i_y >= p_sys->ps_desk_planes[i_plane].i_pce_max_lines / 2))
577 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;
578 else
579 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);
582 #define MAX_SECT 10
584 /*****************************************************************************
585 * generate data which will be used to draw each line of a piece sector with
586 * flat border
587 *****************************************************************************/
588 int puzzle_generate_sect_border( filter_t *p_filter, piece_shape_t *ps_piece_shape, uint8_t i_plane, uint8_t i_border)
590 /* generate data required to draw a sector of border puzzle piece */
591 if (!ps_piece_shape)
592 return VLC_EGENERIC;
594 filter_sys_t *p_sys = p_filter->p_sys;
596 int32_t i_width = p_sys->ps_desk_planes[i_plane].i_pce_max_width;
597 int32_t i_lines = p_sys->ps_desk_planes[i_plane].i_pce_max_lines;
599 /* process each horizontal pixel lines */
600 int32_t i_min_y = (i_border != puzzle_SHAPE_BTM) ? 0 : floor( i_lines / 2 );
602 int32_t i_nb_y = (i_border != puzzle_SHAPE_TOP)?
603 (i_lines - i_min_y) : (i_lines /2 - i_min_y);
605 /* allocate memory */
606 ps_piece_shape->i_row_nbr = i_nb_y;
607 ps_piece_shape->i_first_row_offset = i_min_y;
608 ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t ) * i_nb_y );
609 if (!ps_piece_shape->ps_piece_shape_row)
610 return VLC_ENOMEM;
612 for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++) {
613 uint8_t i_sect = 0;
614 int32_t pi_sects[MAX_SECT];
615 int32_t i_row = i_y - i_min_y;
617 /* ...fill from border to next junction */
618 switch (i_border)
620 case puzzle_SHAPE_TOP:
621 case puzzle_SHAPE_BTM:
622 pi_sects[i_sect] = puzzle_diagonal_limit( p_filter, i_y, false, i_plane ) - 1
623 - (puzzle_diagonal_limit( p_filter, i_y, true, i_plane ) - 1);
624 break;
625 case puzzle_SHAPE_RIGHT:
626 pi_sects[i_sect] = i_width - puzzle_diagonal_limit( p_filter, i_y, false, i_plane );
627 break;
628 case puzzle_SHAPE_LEFT:
629 default:
630 pi_sects[i_sect] = puzzle_diagonal_limit( p_filter, i_y, true, i_plane );
632 i_sect++;
634 /* ...allocate memory and copy final values */
635 ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
636 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc ( sizeof(row_section_t) * i_sect);
637 if (!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
638 for (uint8_t i=0; i<i_row;i++)
639 free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
640 free(ps_piece_shape->ps_piece_shape_row);
641 ps_piece_shape->ps_piece_shape_row = NULL;
642 return VLC_ENOMEM;
645 for (uint8_t i=0; i < i_sect; i++) {
646 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = i % 2; /* 0 = fill ; 1 = offset */
647 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width = pi_sects[i];
650 return VLC_SUCCESS;
653 /*****************************************************************************
654 * generate data which will be used to draw each line of a piece sector based
655 * on bezier curve
656 *****************************************************************************/
657 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)
659 /* generate data required to draw a sector of puzzle piece using bezier shape */
660 if ((!ps_pt) || (!ps_piece_shape))
661 return VLC_EGENERIC;
663 filter_sys_t *p_sys = p_filter->p_sys;
665 int32_t i_width = p_sys->ps_desk_planes[i_plane].i_pce_max_width;
666 int32_t i_lines = p_sys->ps_desk_planes[i_plane].i_pce_max_lines;
667 int32_t i_size_x_0 = p_sys->ps_desk_planes[0].i_pce_max_width;
668 int32_t i_size_y_0 = p_sys->ps_desk_planes[0].i_pce_max_lines;
670 float f_x_ratio = ((float) i_width) / ((float) i_size_x_0);
671 float f_y_ratio = ((float) i_lines) / ((float) i_size_y_0);
673 /* first: get min x and min y */
674 float f_min_curve_x, f_min_curve_y;
675 puzzle_get_min_bezier(&f_min_curve_x, &f_min_curve_y, f_x_ratio, f_y_ratio, ps_pt, i_pts_nbr);
677 f_min_curve_y = __MIN(0,floor(f_min_curve_y));
678 f_min_curve_x = __MIN(0,floor(f_min_curve_x));
680 /* next: process each horizontal pixel lines */
681 int32_t i_min_y = (i_border==puzzle_SHAPE_TOP)?floor(f_min_curve_y):0;
682 int32_t i_nb_y = (i_border==puzzle_SHAPE_TOP)?(i_lines / 2 - i_min_y):i_lines;
684 /* allocate memory */
685 ps_piece_shape->i_row_nbr = i_nb_y;
686 ps_piece_shape->i_first_row_offset = i_min_y;
687 ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t ) * ps_piece_shape->i_row_nbr );
688 if (!ps_piece_shape->ps_piece_shape_row)
689 return VLC_ENOMEM;
691 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);
694 /*****************************************************************************
695 * when generating shape data: determine minimum bezier value
696 *****************************************************************************/
697 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)
699 *f_min_curve_y = ps_pt[0].f_y * f_y_ratio;
700 *f_min_curve_x = ps_pt[0].f_x * f_x_ratio;
702 for (float f_t = 0; f_t <= i_pts_nbr - 1; f_t += 0.1 ) {
703 int8_t i_main_t = floor(f_t);
704 if ( i_main_t == i_pts_nbr - 1 )
705 i_main_t = i_pts_nbr - 2;
706 float f_sub_t = f_t - i_main_t;
708 *f_min_curve_x = __MIN(*f_min_curve_x,bezier_val(ps_pt,f_sub_t,i_main_t,x) * f_x_ratio);
709 *f_min_curve_y = __MIN(*f_min_curve_y,bezier_val(ps_pt,f_sub_t,i_main_t,y) * f_y_ratio);
713 /*****************************************************************************
714 * proceed with each line in order to generate data which will be used
715 * to draw each line of a piece sector
716 *****************************************************************************/
717 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)
719 /* generate data required to draw a line of a piece sector */
720 for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++) {
721 int32_t i_row = i_y - i_min_y;
723 int32_t pi_sects[MAX_SECT];
725 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);
727 /* ...we have to convert absolute values to offsets and take into account min_curve_x */
728 int8_t i_s = 0;
729 int32_t i_last_x = (i_border==puzzle_SHAPE_TOP && (i_y>=0))?puzzle_diagonal_limit( p_filter, i_y, true, i_plane ):0;
731 for (i_s = 0; i_s<i_sect; i_s++) {
732 int32_t i_current_x = pi_sects[i_s];
733 int32_t i_delta = i_current_x - i_last_x;
734 pi_sects[i_s] = i_delta;
736 i_last_x = i_current_x;
739 switch (i_border)
741 case puzzle_SHAPE_TOP:
742 /* ...allocate memory and copy final values */
743 /* note for y > 0 we have to ignore the first offset as it is included in "Left" piece shape */
744 if ( i_y >= 0 ) {
745 ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
746 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc ( sizeof(row_section_t) * i_sect);
747 if (!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
748 for (uint8_t i=0; i<i_row;i++)
749 free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
750 free(ps_piece_shape->ps_piece_shape_row);
751 ps_piece_shape->ps_piece_shape_row = NULL;
752 return VLC_ENOMEM;
754 for (uint8_t i=0; i < i_sect; i++) {
755 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = i % 2; /* 0 = fill ; 1 = offset */
756 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width = pi_sects[i];
759 else {
760 ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
761 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc ( sizeof(row_section_t) * i_sect);
762 if (!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
763 for (uint8_t i=0; i<i_row;i++)
764 free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
765 free(ps_piece_shape->ps_piece_shape_row);
766 ps_piece_shape->ps_piece_shape_row = NULL;
767 return VLC_ENOMEM;
769 for (uint8_t i=0; i < i_sect; i++) {
770 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = (i + 1) % 2; /* 0 = fill ; 1 = offset */
771 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width = pi_sects[i];
774 break;
775 case puzzle_SHAPE_LEFT:
776 /* ...allocate memory and copy final values */
777 /* note for y > 0 we have to ignore the first offset as it is included in "Left" piece shape */
778 ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_sect;
779 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc ( sizeof(row_section_t) * i_sect);
780 if (!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
781 for (uint8_t i=0; i<i_row;i++)
782 free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
783 free(ps_piece_shape->ps_piece_shape_row);
784 ps_piece_shape->ps_piece_shape_row = NULL;
785 return VLC_ENOMEM;
787 for (uint8_t i=0; i < i_sect; i++) {
788 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_type = (i+1) % 2; /* 0 = fill ; 1 = offset */
789 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i].i_width = pi_sects[i];
793 return VLC_SUCCESS;
796 /*****************************************************************************
797 * when generating shape data: detect all bezier curve intersections with
798 * current line
799 *****************************************************************************/
800 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)
802 int8_t i_main_t = 0;
803 float f_xd, f_yd;
804 float f_xo = ps_pt[0].f_x * f_x_ratio;
805 float f_yo = ps_pt[0].f_y * f_y_ratio;
806 int8_t i_sect = 0;
808 for (float f_t = 0; f_t <= i_pts_nbr - 1; f_t += 0.1 ) {
809 i_main_t = floor(f_t);
810 if ( i_main_t == i_pts_nbr - 1 )
811 i_main_t = i_pts_nbr - 2;
812 float f_sub_t = f_t - i_main_t;
814 f_xd = bezier_val(ps_pt,f_sub_t,i_main_t,x) * f_x_ratio;
815 f_yd = bezier_val(ps_pt,f_sub_t,i_main_t,y) * f_y_ratio;
817 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)) {
818 pi_sects[i_sect] = floor(((float)i_y+0.5 - f_yo) * (f_xd - f_xo) / (f_yd - f_yo) + f_xo);
819 if (i_sect < MAX_SECT - 1)
820 i_sect++;
823 f_xo = f_xd;
824 f_yo = f_yd;
826 f_xd = ps_pt[i_pts_nbr - 1].f_x * f_x_ratio;
827 f_yd = ps_pt[i_pts_nbr - 1].f_y * f_y_ratio;
829 /* ...fill from this junction to next junction */
830 if ( i_y >= 0 ) {
831 /* last diagonal intersection */
832 pi_sects[i_sect] = (i_border==puzzle_SHAPE_TOP)?puzzle_diagonal_limit( p_filter, i_y, false, i_plane )
833 :puzzle_diagonal_limit( p_filter, i_y, true, i_plane );
834 if (i_sect < MAX_SECT - 1)
835 i_sect++;
838 /* ...reorder the list of intersection */
839 int32_t i_s = 0;
841 while (i_s < (i_sect - 1)) {
842 if (pi_sects[i_s] > pi_sects[i_s+1]) {
843 uint32_t i_temp = pi_sects[i_s];
844 pi_sects[i_s] = pi_sects[i_s+1];
845 pi_sects[i_s+1] = i_temp;
846 i_s = 0;
848 else {
849 i_s++;
853 return i_sect;
856 /*****************************************************************************
857 * generate Right shape data from Left shape data
858 *****************************************************************************/
859 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)
861 if ((!ps_piece_shape) || (!ps_left_piece_shape))
862 return VLC_EGENERIC;
864 filter_sys_t *p_sys = p_filter->p_sys;
866 int32_t i_min_y = ps_left_piece_shape->i_first_row_offset;
867 int32_t i_nb_y = ps_left_piece_shape->i_row_nbr;
869 /* allocate memory */
870 ps_piece_shape->i_row_nbr = i_nb_y;
871 ps_piece_shape->i_first_row_offset = i_min_y;
872 ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t ) * i_nb_y );
873 if (!ps_piece_shape->ps_piece_shape_row)
874 return VLC_ENOMEM;
876 for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++) {
877 int32_t i_row = i_y - i_min_y;
879 int32_t i_width = p_sys->ps_desk_planes[i_plane].i_pce_max_width;
880 int32_t i_left_width = puzzle_diagonal_limit( p_filter, i_y, true, i_plane );
881 int32_t i_right_width = i_width - puzzle_diagonal_limit( p_filter, i_y, false, i_plane );
882 int16_t i_section_nbr = ps_left_piece_shape->ps_piece_shape_row[i_row].i_section_nbr;
884 ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_section_nbr;
885 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc ( sizeof(row_section_t) * i_section_nbr);
886 if (!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
887 for (uint8_t i=0; i<i_row;i++)
888 free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
889 free(ps_piece_shape->ps_piece_shape_row);
890 ps_piece_shape->ps_piece_shape_row = NULL;
891 return VLC_ENOMEM;
894 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_type =
895 ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_type;
896 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_width =
897 ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_width + i_right_width - i_left_width;
899 for (int8_t i_s=0; i_s<i_section_nbr;i_s++) {
900 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_type =
901 ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_section_nbr - 1 - i_s].i_type;
902 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_width =
903 ps_left_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_section_nbr - 1 - i_s].i_width
904 + (i_s == 0 ? i_right_width - i_left_width : 0);
907 return VLC_SUCCESS;
910 /*****************************************************************************
911 * generates Bottom shape data from Top shape data
912 *****************************************************************************/
913 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)
915 if ((!ps_piece_shape) || (!ps_top_piece_shape))
916 return VLC_EGENERIC;
918 filter_sys_t *p_sys = p_filter->p_sys;
920 int32_t i_top_min_y = ps_top_piece_shape->i_first_row_offset;
921 int32_t i_top_nb_y = ps_top_piece_shape->i_row_nbr;
922 int32_t i_lines = p_sys->ps_desk_planes[i_plane].i_pce_max_lines;
923 int32_t i_max_y = p_sys->ps_desk_planes[i_plane].i_pce_max_lines - i_top_min_y;
925 int32_t i_min_y = i_lines / 2;
926 int32_t i_nb_y = i_max_y - i_min_y;
928 /* allocate memory */
929 ps_piece_shape->i_row_nbr = i_nb_y;
930 ps_piece_shape->i_first_row_offset = i_min_y;
931 ps_piece_shape->ps_piece_shape_row = malloc( sizeof( piece_shape_row_t ) * i_nb_y );
932 if (!ps_piece_shape->ps_piece_shape_row)
933 return VLC_ENOMEM;
935 for (int32_t i_y = i_min_y; i_y < i_nb_y + i_min_y; i_y++) {
936 int32_t i_top_y = 2 * i_min_y - i_y + (i_nb_y - i_top_nb_y);
937 int32_t i_row = i_y - i_min_y;
938 int32_t i_top_row = i_top_y - i_top_min_y;
940 if ( i_top_row < 0 || i_top_row >= i_top_nb_y ) { /* the line does not exist in top */
941 ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = 1;
942 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc ( sizeof(row_section_t) * 1);
943 if (!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
944 for (uint8_t i=0; i<i_row;i++)
945 free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
946 free(ps_piece_shape->ps_piece_shape_row);
947 ps_piece_shape->ps_piece_shape_row = NULL;
948 return VLC_ENOMEM;
950 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_type = 0;
951 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[0].i_width =
952 puzzle_diagonal_limit( p_filter, i_y, false, i_plane ) - 1 - (puzzle_diagonal_limit( p_filter, i_y, true, i_plane ) - 1);
954 else { /* copy the line from TopShape */
955 int32_t i_top_width =
956 puzzle_diagonal_limit( p_filter, i_top_y, false, i_plane ) - 1 - (puzzle_diagonal_limit( p_filter, i_top_y, true, i_plane ) - 1);
957 int32_t i_width =
958 puzzle_diagonal_limit( p_filter, i_y, false, i_plane ) - 1 - (puzzle_diagonal_limit( p_filter, i_y, true, i_plane ) - 1);
959 int32_t i_left_adjust = ( i_width - i_top_width ) / 2;
960 int32_t i_right_adjust = ( i_width - i_top_width ) - i_left_adjust;
962 int8_t i_section_nbr = ps_top_piece_shape->ps_piece_shape_row[i_top_row].i_section_nbr;
963 ps_piece_shape->ps_piece_shape_row[i_row].i_section_nbr = i_section_nbr;
964 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section = malloc ( sizeof(row_section_t) * i_section_nbr);
965 if (!ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section) {
966 for (uint8_t i=0; i<i_row;i++)
967 free(ps_piece_shape->ps_piece_shape_row[i].ps_row_section);
968 free(ps_piece_shape->ps_piece_shape_row);
969 ps_piece_shape->ps_piece_shape_row = NULL;
970 return VLC_ENOMEM;
973 for (int8_t i_s=0; i_s<i_section_nbr; i_s++) {
974 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_type =
975 ps_top_piece_shape->ps_piece_shape_row[i_top_row].ps_row_section[i_s].i_type;
976 ps_piece_shape->ps_piece_shape_row[i_row].ps_row_section[i_s].i_width =
977 ps_top_piece_shape->ps_piece_shape_row[i_top_row].ps_row_section[i_s].i_width
978 + (i_s == 0 ? i_left_adjust : (i_s == i_section_nbr-1 ? i_right_adjust : 0));
982 return VLC_SUCCESS;