1 /*****************************************************************************
2 * ball.c : Augmented reality ball video filter module
3 *****************************************************************************
4 * Copyright (C) 2000-2009 VLC authors and VideoLAN
6 * Author: Adrien Maglo <magsoft@videolan.org>
8 * The Canny edge detection algorithm comes from gradient.c which was
10 * Samuel Hocevar <sam@zoy.org>
11 * Antoine Cellerier <dionoea -at- videolan -dot- org>
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU Lesser General Public License as published by
15 * the Free Software Foundation; either version 2.1 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this program; if not, write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
37 #include <math.h> /* sin(), cos(), asin() */
39 #include <vlc_common.h>
40 #include <vlc_plugin.h>
41 #include <vlc_picture.h>
42 #include <vlc_filter.h>
43 #include "filter_picture.h"
44 #include <vlc_image.h>
46 enum { RED
, GREEN
, BLUE
, WHITE
};
49 p_sys->colorList[RED].comp1 = 255; p_sys->colorList[RED].comp2 = 0; \
50 p_sys->colorList[RED].comp3 = 0; \
51 p_sys->colorList[GREEN].comp1 = 0; p_sys->colorList[GREEN].comp2 = 255; \
52 p_sys->colorList[GREEN].comp3 = 0; \
53 p_sys->colorList[BLUE].comp1 = 0; p_sys->colorList[BLUE].comp2 = 0; \
54 p_sys->colorList[BLUE].comp3 = 255; \
55 p_sys->colorList[WHITE].comp1 = 255; p_sys->colorList[WHITE].comp2 = 255; \
56 p_sys->colorList[WHITE].comp3 = 255;
59 p_sys->colorList[RED].comp1 = 82; p_sys->colorList[RED].comp2 = 240; \
60 p_sys->colorList[RED].comp3 = 90; \
61 p_sys->colorList[GREEN].comp1 = 145; p_sys->colorList[GREEN].comp2 = 34; \
62 p_sys->colorList[GREEN].comp3 = 54 ; \
63 p_sys->colorList[BLUE].comp1 = 41; p_sys->colorList[BLUE].comp2 = 146; \
64 p_sys->colorList[BLUE].comp3 = 240; \
65 p_sys->colorList[WHITE].comp1 = 255; p_sys->colorList[WHITE].comp2 = 128; \
66 p_sys->colorList[WHITE].comp3 = 128;
69 /*****************************************************************************
71 *****************************************************************************/
73 typedef struct filter_sys_t filter_sys_t
;
75 static int Create ( filter_t
* );
77 VIDEO_FILTER_WRAPPER_CLOSE( Filter
, Destroy
)
79 static void drawBall( filter_sys_t
*p_sys
, picture_t
*p_outpic
);
80 static void drawPixelRGB24( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
81 uint8_t R
, uint8_t G
, uint8_t B
,
82 int x
, int y
, bool b_skip
);
83 static void drawPixelI420( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
84 uint8_t Y
, uint8_t U
, uint8_t V
,
85 int x
, int y
, bool b_skip
);
86 static void drawPixelPacked( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
87 uint8_t Y
, uint8_t U
, uint8_t V
,
88 int x
, int y
, bool b_skip
);
90 static void FilterBall( filter_t
*, picture_t
*, picture_t
* );
91 static int ballCallback( vlc_object_t
*, char const *,
92 vlc_value_t
, vlc_value_t
,
94 static int getBallColor( vlc_object_t
*p_this
, char const *psz_newval
);
97 /*****************************************************************************
99 *****************************************************************************/
100 #define BALL_COLOR_TEXT N_("Ball color")
102 #define EDGE_VISIBLE_TEXT N_("Edge visible")
103 #define EDGE_VISIBLE_LONGTEXT N_("Set edge visibility.")
105 #define BALL_SPEED_TEXT N_("Ball speed")
106 #define BALL_SPEED_LONGTEXT N_("Set ball speed, the displacement value " \
107 "in number of pixels by frame.")
109 #define BALL_SIZE_TEXT N_("Ball size")
110 #define BALL_SIZE_LONGTEXT N_("Set ball size giving its radius in number " \
113 #define GRAD_THRESH_TEXT N_("Gradient threshold")
114 #define GRAD_THRESH_LONGTEXT N_("Set gradient threshold for edge computation.")
116 #define BALL_HELP N_("Augmented reality ball game")
118 #define FILTER_PREFIX "ball-"
120 static const char *const mode_list
[] = { "red", "green", "blue", "white" };
121 static const char *const mode_list_text
[] = { N_("Red"), N_("Green"),
122 N_("Blue"), N_("White") };
125 set_description( N_("Ball video filter") )
126 set_shortname( N_( "Ball" ))
128 set_category( CAT_VIDEO
)
129 set_subcategory( SUBCAT_VIDEO_VFILTER
)
131 add_string( FILTER_PREFIX
"color", "red",
132 BALL_COLOR_TEXT
, BALL_COLOR_TEXT
, false )
133 change_string_list( mode_list
, mode_list_text
)
135 add_integer_with_range( FILTER_PREFIX
"speed", 4, 1, 15,
136 BALL_SPEED_TEXT
, BALL_SPEED_LONGTEXT
, false )
138 add_integer_with_range( FILTER_PREFIX
"size", 10, 5, 30,
139 BALL_SIZE_TEXT
, BALL_SIZE_LONGTEXT
, false )
141 add_integer_with_range( FILTER_PREFIX
"gradient-threshold", 40, 1, 200,
142 GRAD_THRESH_TEXT
, GRAD_THRESH_LONGTEXT
, false )
144 add_bool( FILTER_PREFIX
"edge-visible", true,
145 EDGE_VISIBLE_TEXT
, EDGE_VISIBLE_LONGTEXT
, true )
147 add_shortcut( "ball" )
148 set_callback_video_filter( Create
)
151 static const char *const ppsz_filter_options
[] = {
152 "color", "speed", "size",
153 "gradient-threshold", "edge-visible", NULL
157 /*****************************************************************************
158 * filter_sys_t: Distort video output method descriptor
159 *****************************************************************************
160 * This structure is part of the video output thread descriptor.
161 * It describes the Distort specific properties of an output thread.
162 *****************************************************************************/
169 image_handler_t
*p_image
;
181 /* Offsets for YUV packed chroma */
186 /* Gradient values */
191 /* Gradient threshold */
204 /* Pointer on drawing function */
205 void ( *drawingPixelFunction
)( filter_sys_t
*, picture_t
*,
206 uint8_t, uint8_t, uint8_t,
216 /*****************************************************************************
217 * Create: allocates Distort video thread output method
218 *****************************************************************************
219 * This function allocates and initializes a Distort vout method.
220 *****************************************************************************/
221 static int Create( filter_t
*p_filter
)
225 /* Allocate structure */
226 filter_sys_t
*p_sys
= malloc( sizeof( filter_sys_t
) );
229 p_filter
->p_sys
= p_sys
;
231 switch( p_filter
->fmt_in
.video
.i_chroma
)
235 p_sys
->drawingPixelFunction
= drawPixelI420
;
239 p_sys
->drawingPixelFunction
= drawPixelPacked
;
241 GetPackedYuvOffsets( p_filter
->fmt_in
.video
.i_chroma
,
244 &p_sys
->i_v_offset
);
246 case VLC_CODEC_RGB24
:
247 p_sys
->drawingPixelFunction
= drawPixelRGB24
;
251 msg_Err( p_filter
, "Unsupported input chroma (%4.4s)",
252 (char*)&(p_filter
->fmt_in
.video
.i_chroma
) );
256 p_sys
->p_image
= image_HandlerCreate( p_filter
);
257 if( p_sys
->p_image
== NULL
)
260 p_filter
->ops
= &Filter_ops
;
262 config_ChainParse( p_filter
, FILTER_PREFIX
, ppsz_filter_options
,
266 var_CreateGetNonEmptyStringCommand( p_filter
,
267 FILTER_PREFIX
"color" ) ) )
269 msg_Err( p_filter
, "configuration variable "
270 FILTER_PREFIX
"color empty" );
271 p_sys
->ballColor
= RED
;
274 p_sys
->ballColor
= getBallColor( VLC_OBJECT(p_filter
), psz_method
);
279 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"size" );
281 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"speed" );
282 p_sys
->b_edgeVisible
=
283 var_CreateGetBoolCommand( p_filter
, FILTER_PREFIX
"edge-visible" );
284 p_sys
->i_gradThresh
=
285 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"gradient-threshold" );
287 vlc_mutex_init( &p_sys
->lock
);
289 var_AddCallback( p_filter
, FILTER_PREFIX
"color",
290 ballCallback
, p_sys
);
291 var_AddCallback( p_filter
, FILTER_PREFIX
"size",
292 ballCallback
, p_sys
);
293 var_AddCallback( p_filter
, FILTER_PREFIX
"speed",
294 ballCallback
, p_sys
);
295 var_AddCallback( p_filter
, FILTER_PREFIX
"edge-visible",
296 ballCallback
, p_sys
);
298 p_sys
->p_smooth
= NULL
;
299 p_sys
->p_grad_x
= NULL
;
300 p_sys
->p_grad_y
= NULL
;
302 p_sys
->i_ball_x
= 100;
303 p_sys
->i_ball_y
= 100;
305 p_sys
->f_lastVect_x
= 0;
306 p_sys
->f_lastVect_y
= -1;
312 /*****************************************************************************
313 * Destroy: destroy Distort video thread output method
314 *****************************************************************************
315 * Terminate an output method created by DistortCreateOutputMethod
316 *****************************************************************************/
317 static void Destroy( filter_t
*p_filter
)
319 filter_sys_t
*p_sys
= p_filter
->p_sys
;
321 var_DelCallback( p_filter
, FILTER_PREFIX
"color",
322 ballCallback
, p_sys
);
323 var_DelCallback( p_filter
, FILTER_PREFIX
"size",
324 ballCallback
, p_sys
);
325 var_DelCallback( p_filter
, FILTER_PREFIX
"speed",
326 ballCallback
, p_sys
);
327 var_DelCallback( p_filter
, FILTER_PREFIX
"edge-visible",
328 ballCallback
, p_sys
);
330 image_HandlerDelete( p_sys
->p_image
);
332 free( p_sys
->p_smooth
);
333 free( p_sys
->p_grad_x
);
334 free( p_sys
->p_grad_y
);
340 /*****************************************************************************
341 * Render: displays previously rendered output
342 *****************************************************************************
343 * This function send the currently rendered image to Distort image, waits
344 * until it is displayed and switch the two rendering buffers, preparing next
346 *****************************************************************************/
347 static void Filter( filter_t
*p_filter
, picture_t
*p_pic
, picture_t
*p_outpic
)
349 filter_sys_t
*p_sys
= p_filter
->p_sys
;
350 vlc_mutex_lock( &p_sys
->lock
);
351 FilterBall( p_filter
, p_pic
, p_outpic
);
352 vlc_mutex_unlock( &p_sys
->lock
);
355 /*****************************************************************************
357 *****************************************************************************/
359 static void drawBall( filter_sys_t
*p_sys
, picture_t
*p_outpic
)
361 int x
= p_sys
->i_ball_x
;
362 int y
= p_sys
->i_ball_y
;
363 int size
= p_sys
->i_ballSize
;
365 const int i_width
= p_outpic
->p
[0].i_visible_pitch
;
366 const int i_height
= p_outpic
->p
[0].i_visible_lines
;
368 for( int j
= y
- size
; j
<= y
+ size
; j
++ )
370 bool b_skip
= ( x
- size
) % 2;
371 for( int i
= x
- size
; i
<= x
+ size
; i
++ )
373 /* Draw the pixel if it is inside the disk
374 and check we don't write out the frame. */
375 if( ( i
- x
) * ( i
- x
) + ( j
- y
) * ( j
- y
) <= size
* size
376 && i
>= 0 && i
< i_width
377 && j
>= 0 && j
< i_height
)
379 ( *p_sys
->drawingPixelFunction
)( p_sys
, p_outpic
,
380 p_sys
->colorList
[ p_sys
->ballColor
].comp1
,
381 p_sys
->colorList
[ p_sys
->ballColor
].comp2
,
382 p_sys
->colorList
[ p_sys
->ballColor
].comp3
,
391 static void drawPixelRGB24( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
392 uint8_t R
, uint8_t G
, uint8_t B
,
393 int x
, int y
, bool b_skip
)
396 VLC_UNUSED( b_skip
);
397 uint8_t *p_pixel
= p_outpic
->p
[0].p_pixels
398 + p_outpic
->p
[0].i_pitch
406 static void drawPixelI420( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
407 uint8_t Y
, uint8_t U
, uint8_t V
,
408 int x
, int y
, bool b_skip
)
411 *( p_outpic
->p
[0].p_pixels
+ p_outpic
->p
[0].i_pitch
* y
+ x
) = Y
;
414 *( p_outpic
->p
[2].p_pixels
+ p_outpic
->p
[2].i_pitch
415 * ( y
/ 2 ) + x
/ 2 ) = U
;
416 *( p_outpic
->p
[1].p_pixels
+ p_outpic
->p
[1].i_pitch
417 * ( y
/ 2 ) + x
/ 2 ) = V
;
422 static void drawPixelPacked( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
423 uint8_t Y
, uint8_t U
, uint8_t V
,
424 int x
, int y
, bool b_skip
)
426 uint8_t *p_pixel
= p_outpic
->p
[0].p_pixels
427 + p_outpic
->p
[0].i_pitch
* y
+ x
* 2;
428 *( p_pixel
+ p_sys
->i_y_offset
) = Y
;
431 *( p_pixel
+ p_sys
->i_u_offset
) = U
;
432 *( p_pixel
+ p_sys
->i_v_offset
) = V
;
437 /*****************************************************************************
439 *****************************************************************************
440 * Modify its value to set its norm to 1 and keep its direction.
441 *****************************************************************************/
442 static void NormalizeVector( float *vect_x
, float *vect_y
)
444 float norm
= sqrt( *vect_x
* *vect_x
+ *vect_y
* *vect_y
);
445 if( *vect_x
!= 0 || *vect_y
!= 0 )
453 /*****************************************************************************
454 * Gaussian Convolution
455 *****************************************************************************
456 * Gaussian convolution ( sigma == 1.4 )
458 * | 2 4 5 4 2 | | 2 4 4 4 2 |
459 * | 4 9 12 9 4 | | 4 8 12 8 4 |
460 * | 5 12 15 12 5 | ~ | 4 12 16 12 4 |
461 * | 4 9 12 9 4 | | 4 8 12 8 4 |
462 * | 2 4 5 4 2 | | 2 4 4 4 2 |
463 *****************************************************************************/
464 static void GaussianConvolution( picture_t
*p_inpic
, uint32_t *p_smooth
)
466 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
467 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
468 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
469 const int i_numLines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
471 for( int y
= 2; y
< i_numLines
- 2; y
++ )
473 for( int x
= 2; x
< i_src_visible
- 2; x
++ )
475 p_smooth
[y
*i_src_visible
+x
] = (uint32_t)(
477 ( p_inpix
[(y
-2)*i_src_pitch
+x
-2] )
478 + ((p_inpix
[(y
-2)*i_src_pitch
+x
-1]
479 + p_inpix
[(y
-2)*i_src_pitch
+x
]
480 + p_inpix
[(y
-2)*i_src_pitch
+x
+1])<<1 )
481 + ( p_inpix
[(y
-2)*i_src_pitch
+x
+2] )
483 + ((p_inpix
[(y
-1)*i_src_pitch
+x
-2]
484 + ( p_inpix
[(y
-1)*i_src_pitch
+x
-1]<<1 )
485 + ( p_inpix
[(y
-1)*i_src_pitch
+x
]*3 )
486 + ( p_inpix
[(y
-1)*i_src_pitch
+x
+1]<<1 )
487 + p_inpix
[(y
-1)*i_src_pitch
+x
+2]
489 + p_inpix
[y
*i_src_pitch
+x
-2]
490 + ( p_inpix
[y
*i_src_pitch
+x
-1]*3 )
491 + ( p_inpix
[y
*i_src_pitch
+x
]<<2 )
492 + ( p_inpix
[y
*i_src_pitch
+x
+1]*3 )
493 + p_inpix
[y
*i_src_pitch
+x
+2]
495 + p_inpix
[(y
+1)*i_src_pitch
+x
-2]
496 + ( p_inpix
[(y
+1)*i_src_pitch
+x
-1]<<1 )
497 + ( p_inpix
[(y
+1)*i_src_pitch
+x
]*3 )
498 + ( p_inpix
[(y
+1)*i_src_pitch
+x
+1]<<1 )
499 + p_inpix
[(y
+1)*i_src_pitch
+x
+2] )<<1 )
501 + ( p_inpix
[(y
+2)*i_src_pitch
+x
-2] )
502 + ((p_inpix
[(y
+2)*i_src_pitch
+x
-1]
503 + p_inpix
[(y
+2)*i_src_pitch
+x
]
504 + p_inpix
[(y
+2)*i_src_pitch
+x
+1])<<1 )
505 + ( p_inpix
[(y
+2)*i_src_pitch
+x
+2] )
512 /*****************************************************************************
513 * FilterBall: Augmented reality ball video filter
514 *****************************************************************************
515 * The edge detection part comes from gradient.c video filter module.
516 * The Canny edge detection algorithm is used :
517 * http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
518 * (well ... the implementation isn't really the canny algorithm ... but some
519 * ideas are the same)
520 *****************************************************************************/
521 static void FilterBall( filter_t
*p_filter
, picture_t
*p_inpic
,
522 picture_t
*p_outpic
)
525 filter_sys_t
*p_sys
= p_filter
->p_sys
;
531 picture_t
*p_converted
;
532 video_format_t fmt_comp
;
534 switch( p_filter
->fmt_in
.video
.i_chroma
)
536 case VLC_CODEC_RGB24
:
538 video_format_Init( &fmt_comp
, VLC_CODEC_GREY
);
539 fmt_comp
.i_width
= p_filter
->fmt_in
.video
.i_width
;
540 fmt_comp
.i_height
= p_filter
->fmt_in
.video
.i_height
;
541 fmt_comp
.i_visible_width
= fmt_comp
.i_width
;
542 fmt_comp
.i_visible_height
= fmt_comp
.i_height
;
544 p_converted
= image_Convert( p_sys
->p_image
, p_inpic
,
545 &(p_filter
->fmt_in
.video
),
547 video_format_Clean( &fmt_comp
);
554 p_converted
= p_inpic
;
558 const int i_numCols
= p_converted
->p
[0].i_visible_pitch
;
559 const int i_numLines
= p_converted
->p
[0].i_visible_lines
;
561 if( !p_sys
->p_smooth
)
563 (uint32_t *)vlc_alloc( i_numLines
* i_numCols
,
565 p_smooth
= p_sys
->p_smooth
;
567 if( !p_sys
->p_grad_x
)
569 (int32_t *)vlc_alloc( i_numLines
* i_numCols
,
571 p_grad_x
= p_sys
->p_grad_x
;
573 if( !p_sys
->p_grad_y
)
575 (int32_t *)vlc_alloc( i_numLines
* i_numCols
,
577 p_grad_y
= p_sys
->p_grad_y
;
579 if( !p_smooth
|| !p_grad_x
|| !p_grad_y
) return;
581 memcpy( p_outpic
->p
[0].p_pixels
, p_inpic
->p
[0].p_pixels
,
582 p_outpic
->p
[0].i_lines
* p_outpic
->p
[0].i_pitch
);
583 memcpy( p_outpic
->p
[1].p_pixels
, p_inpic
->p
[1].p_pixels
,
584 p_outpic
->p
[1].i_lines
* p_outpic
->p
[1].i_pitch
);
585 memcpy( p_outpic
->p
[2].p_pixels
, p_inpic
->p
[2].p_pixels
,
586 p_outpic
->p
[2].i_lines
* p_outpic
->p
[2].i_pitch
);
588 GaussianConvolution( p_converted
, p_smooth
);
590 /* Compute the picture Sobel gradient
592 | -2 0 2 | and | 0 0 0 |
593 | -1 0 1 | | -1 -2 -1 | */
595 for( int line
= 1; line
< i_numLines
- 1; line
++ )
597 for( int col
= 1; col
< i_numCols
- 1; col
++ )
600 p_grad_x
[ line
* i_numCols
+ col
] =
601 ( p_smooth
[(line
-1)*i_numCols
+col
-1]
602 - p_smooth
[(line
+1)*i_numCols
+col
-1] )
603 + ( ( p_smooth
[(line
-1)*i_numCols
+col
]
604 - p_smooth
[(line
+1)*i_numCols
+col
] ) <<1 )
605 + ( p_smooth
[(line
-1)*i_numCols
+col
+1]
606 - p_smooth
[(line
+1)*i_numCols
+col
+1] );
607 p_grad_y
[ line
* i_numCols
+ col
] =
608 ( p_smooth
[(line
-1)*i_numCols
+col
-1]
609 - p_smooth
[(line
-1)*i_numCols
+col
+1] )
610 + ( ( p_smooth
[line
*i_numCols
+col
-1]
611 - p_smooth
[line
*i_numCols
+col
+1] ) <<1 )
612 + ( p_smooth
[(line
+1)*i_numCols
+col
-1]
613 - p_smooth
[(line
+1)*i_numCols
+col
+1] );
617 if( p_sys
->b_edgeVisible
)
619 /* Display the edges. */
620 for( int line
= 1; line
< i_numLines
- 1; line
++ )
622 for( int col
= 1; col
< i_numCols
- 1; col
++ )
624 if( abs( p_grad_x
[ line
* i_numCols
+ col
] )
625 + abs( p_grad_y
[ line
* i_numCols
+ col
] )
626 > p_sys
->i_gradThresh
)
628 ( *p_sys
->drawingPixelFunction
)( p_sys
, p_outpic
,
629 p_sys
->colorList
[ WHITE
].comp1
,
630 p_sys
->colorList
[ WHITE
].comp2
,
631 p_sys
->colorList
[ WHITE
].comp3
,
640 float *pf_lastVect_x
= &p_sys
->f_lastVect_x
;
641 float *pf_lastVect_y
= &p_sys
->f_lastVect_y
;
643 float f_newVect_x
= 0;
644 float f_newVect_y
= 0;
645 float f_contVect_x
= 0;
646 float f_contVect_y
= 0;
648 int nb_collisions
= 0;
652 /* Test collisions for each pixel the ball will cover in its
654 for ( i_motion
= 0; i_motion
<= p_sys
->i_ballSpeed
&& !bounce
; i_motion
++ )
656 /* Compute next ball position */
657 x
= roundf( (float)p_sys
->i_ball_x
658 + *pf_lastVect_x
* (float)i_motion
);
659 y
= roundf( (float)p_sys
->i_ball_y
660 + *pf_lastVect_y
* (float)i_motion
);
662 for( int i
= x
- p_sys
->i_ballSize
; i
<= x
+ p_sys
->i_ballSize
; i
++ )
664 for( int j
= y
- p_sys
->i_ballSize
;
665 j
<= y
+ p_sys
->i_ballSize
; j
++ )
667 /* Test the pixel if it is inside the disk and check we don't
668 write out the frame. */
669 if( ( i
- x
) * ( i
- x
) + ( j
- y
) * ( j
- y
)
670 == p_sys
->i_ballSize
* p_sys
->i_ballSize
671 && j
<= i_numLines
- 1 && x
<= i_numCols
- 1
672 && j
>= 0 && i
>= 0 )
674 /* Test firstly the picture limit collisions. */
677 f_contVect_x
= x
- i
;
687 f_contVect_y
= y
- j
;
693 if( j
>= i_numLines
- 3 )
696 f_contVect_y
= y
- j
;
702 if( i
>= i_numCols
- 3 )
704 f_contVect_x
= x
- i
;
711 /* Test the collisions with edges. */
712 if( abs( p_grad_x
[ j
* i_numCols
+ i
] )
713 + abs( p_grad_y
[ j
* i_numCols
+ i
] )
714 > p_sys
->i_gradThresh
)
716 f_contVect_x
+= x
- i
;
717 f_contVect_y
+= y
- j
;
730 /* Compute normal vector. */
731 f_contVect_x
/= nb_collisions
;
732 f_contVect_y
/= nb_collisions
;
733 NormalizeVector( &f_contVect_x
, &f_contVect_y
);
735 /* Compute the new vector after the bounce. */
736 float cosinus
= *pf_lastVect_x
* f_contVect_x
737 + *pf_lastVect_y
* f_contVect_y
;
738 f_newVect_x
= *pf_lastVect_x
- 2 * cosinus
* f_contVect_x
;
739 f_newVect_y
= *pf_lastVect_y
- 2 * cosinus
* f_contVect_y
;
740 NormalizeVector( &f_newVect_x
, &f_newVect_y
);
742 *pf_lastVect_x
= f_newVect_x
;
743 *pf_lastVect_y
= f_newVect_y
;
748 /* Test if next pixel is outside the frame limits.
749 If it is the case, then the ball is blocked until it can move. */
750 x
= roundf( (float)x
+ *pf_lastVect_x
);
751 y
= roundf( (float)y
+ *pf_lastVect_y
);
752 if( x
- p_sys
->i_ballSize
< 2
753 || x
+ p_sys
->i_ballSize
> i_numCols
- 3
754 || y
- p_sys
->i_ballSize
< 2
755 || y
+ p_sys
->i_ballSize
> i_numLines
- 3 )
761 /* After a bouce, the first ball motion is always one pixel. */
762 i_motion
= p_sys
->i_ballSpeed
- 1;
767 /* Compute next ball position. */
768 p_sys
->i_ball_x
= roundf( (float)p_sys
->i_ball_x
+ *pf_lastVect_x
769 * (float)( p_sys
->i_ballSpeed
- i_motion
) );
770 p_sys
->i_ball_y
= roundf( p_sys
->i_ball_y
+ *pf_lastVect_y
771 * (float)( p_sys
->i_ballSpeed
- i_motion
) );
774 drawBall( p_sys
, p_outpic
);
776 switch( p_filter
->fmt_in
.video
.i_chroma
)
778 case VLC_CODEC_RGB24
:
780 picture_Release( p_converted
);
787 /*****************************************************************************
789 *****************************************************************************
790 * filter parameter modification callback
791 *****************************************************************************/
792 static int ballCallback( vlc_object_t
*p_this
, char const *psz_var
,
793 vlc_value_t oldval
, vlc_value_t newval
,
797 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
798 msg_Err( p_this
, "Test" );
800 vlc_mutex_lock( &p_sys
->lock
);
801 if( !strcmp( psz_var
, FILTER_PREFIX
"color" ) )
803 p_sys
->ballColor
= getBallColor( p_this
, newval
.psz_string
);
805 else if( !strcmp( psz_var
, FILTER_PREFIX
"size" ) )
807 p_sys
->i_ballSize
= newval
.i_int
;
809 else if( !strcmp( psz_var
, FILTER_PREFIX
"speed" ) )
811 p_sys
->i_ballSpeed
= newval
.i_int
;
813 else if( !strcmp( psz_var
, FILTER_PREFIX
"edge-visible" ) )
815 p_sys
->b_edgeVisible
= newval
.b_bool
;
817 else if( !strcmp( psz_var
, FILTER_PREFIX
"gradient-threshold" ) )
819 p_sys
->i_gradThresh
= newval
.i_int
;
821 vlc_mutex_unlock( &p_sys
->lock
);
827 /*****************************************************************************
829 *****************************************************************************
830 * Get and assign the ball color value
831 *****************************************************************************/
832 static int getBallColor( vlc_object_t
*p_this
, char const *psz_newval
)
835 if( !strcmp( psz_newval
, "red" ) )
837 else if( !strcmp( psz_newval
, "blue" ) )
839 else if( !strcmp( psz_newval
, "green" ) )
841 else if( !strcmp( psz_newval
, "white" ) )
845 msg_Err( p_this
, "no valid ball color provided (%s)", psz_newval
);