1 /*****************************************************************************
2 * ball.c : Augmented reality ball video filter module
3 *****************************************************************************
4 * Copyright (C) 2000-2009 the VideoLAN team
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
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 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 General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, 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>
42 #include "vlc_filter.h"
43 #include "filter_picture.h"
44 #include "vlc_image.h"
46 enum { RED
, GREEN
, BLUE
, WHITE
};
55 static COLOR colorList
[4];
58 colorList[RED].comp1 = 255; colorList[RED].comp2 = 0; \
59 colorList[RED].comp3 = 0; \
60 colorList[GREEN].comp1 = 0; colorList[GREEN].comp2 = 255; \
61 colorList[GREEN].comp3 = 0; \
62 colorList[BLUE].comp1 = 0; colorList[BLUE].comp2 = 0; \
63 colorList[BLUE].comp3 = 255; \
64 colorList[WHITE].comp1 = 255; colorList[WHITE].comp2 = 255; \
65 colorList[WHITE].comp3 = 255;
68 colorList[RED].comp1 = 82; colorList[RED].comp2 = 240; \
69 colorList[RED].comp3 = 90; \
70 colorList[GREEN].comp1 = 145; colorList[GREEN].comp2 = 34; \
71 colorList[GREEN].comp3 = 54 ; \
72 colorList[BLUE].comp1 = 41; colorList[BLUE].comp2 = 146; \
73 colorList[BLUE].comp3 = 240; \
74 colorList[WHITE].comp1 = 255; colorList[WHITE].comp2 = 128; \
75 colorList[WHITE].comp3 = 128;
78 /*****************************************************************************
80 *****************************************************************************/
81 static int Create ( vlc_object_t
* );
82 static void Destroy ( vlc_object_t
* );
84 static picture_t
*Filter( filter_t
*, picture_t
* );
86 static void drawBall( filter_sys_t
*p_sys
, picture_t
*p_outpic
);
87 static void drawPixelRGB24( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
88 uint8_t R
, uint8_t G
, uint8_t B
,
89 int x
, int y
, bool b_skip
);
90 static void drawPixelI420( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
91 uint8_t Y
, uint8_t U
, uint8_t V
,
92 int x
, int y
, bool b_skip
);
93 static void drawPixelPacked( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
94 uint8_t Y
, uint8_t U
, uint8_t V
,
95 int x
, int y
, bool b_skip
);
97 static void FilterBall( filter_t
*, picture_t
*, picture_t
* );
98 static int ballCallback( vlc_object_t
*, char const *,
99 vlc_value_t
, vlc_value_t
,
101 static int getBallColor( vlc_object_t
*p_this
, char const *psz_newval
);
104 /*****************************************************************************
106 *****************************************************************************/
107 #define BALL_COLOR_TEXT N_("Ball color")
108 #define BALL_COLOR_LONGTEXT N_("Ball color, one of \"red\", \"blue\" and \"green\".")
110 #define EDGE_VISIBLE_TEXT N_("Edge visible")
111 #define EDGE_VISIBLE_LONGTEXT N_("Set edge visibility.")
113 #define BALL_SPEED_TEXT N_("Ball speed")
114 #define BALL_SPEED_LONGTEXT N_("Set ball speed, the displacement value \
115 in number of pixels by frame.")
117 #define BALL_SIZE_TEXT N_("Ball size")
118 #define BALL_SIZE_LONGTEXT N_("Set ball size giving its radius in number \
121 #define GRAD_THRESH_TEXT N_("Gradient threshold")
122 #define GRAD_THRESH_LONGTEXT N_("Set gradient threshold for edge computation.")
124 #define BALL_HELP N_("Augmented reality ball game")
126 #define FILTER_PREFIX "ball-"
128 static const char *const mode_list
[] = { "red", "green", "blue", "white" };
129 static const char *const mode_list_text
[] = { N_("Red"), N_("Green"),
130 N_("Blue"), N_("White") };
133 set_description( N_("Ball video filter") )
134 set_shortname( N_( "Ball" ))
136 set_capability( "video filter2", 0 )
137 set_category( CAT_VIDEO
)
138 set_subcategory( SUBCAT_VIDEO_VFILTER
)
140 add_string( FILTER_PREFIX
"color", "ball-color",
141 BALL_COLOR_TEXT
, BALL_COLOR_LONGTEXT
, false )
142 change_string_list( mode_list
, mode_list_text
, 0 )
144 add_integer_with_range( FILTER_PREFIX
"speed", 4, 1, 15, NULL
,
145 BALL_SPEED_TEXT
, BALL_SPEED_LONGTEXT
, false )
147 add_integer_with_range( FILTER_PREFIX
"size", 10, 5, 30, NULL
,
148 BALL_SIZE_TEXT
, BALL_SIZE_LONGTEXT
, false )
150 add_integer_with_range( FILTER_PREFIX
"gradient-threshold", 40, 1, 200, NULL
,
151 GRAD_THRESH_TEXT
, GRAD_THRESH_LONGTEXT
, false )
153 add_bool( FILTER_PREFIX
"edge-visible", true, NULL
,
154 EDGE_VISIBLE_TEXT
, EDGE_VISIBLE_LONGTEXT
, true )
156 add_shortcut( "ball" )
157 set_callbacks( Create
, Destroy
)
160 static const char *const ppsz_filter_options
[] = {
161 "ball-color", "ball-speed", "ball-size",
162 "gradient-threshold", "edge-visible", NULL
166 /*****************************************************************************
167 * filter_sys_t: Distort video output method descriptor
168 *****************************************************************************
169 * This structure is part of the video output thread descriptor.
170 * It describes the Distort specific properties of an output thread.
171 *****************************************************************************/
178 image_handler_t
*p_image
;
190 /* Offsets for YUV packed chroma */
195 /* Gradient values */
200 /* Gradient threshold */
213 /* Pointer on drawing function */
214 void ( *drawingPixelFunction
)( filter_sys_t
*, picture_t
*,
215 uint8_t, uint8_t, uint8_t,
220 /*****************************************************************************
221 * Create: allocates Distort video thread output method
222 *****************************************************************************
223 * This function allocates and initializes a Distort vout method.
224 *****************************************************************************/
225 static int Create( vlc_object_t
*p_this
)
227 filter_t
*p_filter
= (filter_t
*)p_this
;
230 /* Allocate structure */
231 p_filter
->p_sys
= malloc( sizeof( filter_sys_t
) );
232 if( p_filter
->p_sys
== NULL
)
235 switch( p_filter
->fmt_in
.video
.i_chroma
)
239 p_filter
->p_sys
->drawingPixelFunction
= drawPixelI420
;
243 p_filter
->p_sys
->drawingPixelFunction
= drawPixelPacked
;
245 GetPackedYuvOffsets( p_filter
->fmt_in
.video
.i_chroma
,
246 &p_filter
->p_sys
->i_y_offset
,
247 &p_filter
->p_sys
->i_u_offset
,
248 &p_filter
->p_sys
->i_v_offset
);
250 case VLC_CODEC_RGB24
:
251 p_filter
->p_sys
->drawingPixelFunction
= drawPixelRGB24
;
255 msg_Err( p_filter
, "Unsupported input chroma (%4.4s)",
256 (char*)&(p_filter
->fmt_in
.video
.i_chroma
) );
260 p_filter
->p_sys
->p_image
= image_HandlerCreate( p_filter
);
261 if( p_filter
->p_sys
->p_image
== NULL
)
264 p_filter
->pf_video_filter
= Filter
;
266 config_ChainParse( p_filter
, FILTER_PREFIX
, ppsz_filter_options
,
270 var_CreateGetNonEmptyStringCommand( p_filter
,
271 FILTER_PREFIX
"color" ) ) )
273 msg_Err( p_filter
, "configuration variable "
274 FILTER_PREFIX
"color empty" );
275 p_filter
->p_sys
->ballColor
= RED
;
278 p_filter
->p_sys
->ballColor
= getBallColor( p_this
, psz_method
);
282 p_filter
->p_sys
->i_ballSize
=
283 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"size" );
284 p_filter
->p_sys
->i_ballSpeed
=
285 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"speed" );
286 p_filter
->p_sys
->b_edgeVisible
=
287 var_CreateGetBoolCommand( p_filter
, FILTER_PREFIX
"edge-visible" );
288 p_filter
->p_sys
->i_gradThresh
=
289 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"gradient-threshold" );
291 vlc_mutex_init( &p_filter
->p_sys
->lock
);
293 var_AddCallback( p_filter
, FILTER_PREFIX
"color",
294 ballCallback
, p_filter
->p_sys
);
295 var_AddCallback( p_filter
, FILTER_PREFIX
"size",
296 ballCallback
, p_filter
->p_sys
);
297 var_AddCallback( p_filter
, FILTER_PREFIX
"speed",
298 ballCallback
, p_filter
->p_sys
);
299 var_AddCallback( p_filter
, FILTER_PREFIX
"edge-visible",
300 ballCallback
, p_filter
->p_sys
);
302 p_filter
->p_sys
->p_smooth
= NULL
;
303 p_filter
->p_sys
->p_grad_x
= NULL
;
304 p_filter
->p_sys
->p_grad_y
= NULL
;
306 p_filter
->p_sys
->i_ball_x
= 100;
307 p_filter
->p_sys
->i_ball_y
= 100;
309 p_filter
->p_sys
->f_lastVect_x
= 0;
310 p_filter
->p_sys
->f_lastVect_y
= -1;
316 /*****************************************************************************
317 * Destroy: destroy Distort video thread output method
318 *****************************************************************************
319 * Terminate an output method created by DistortCreateOutputMethod
320 *****************************************************************************/
321 static void Destroy( vlc_object_t
*p_this
)
323 filter_t
*p_filter
= (filter_t
*)p_this
;
324 filter_sys_t
*p_sys
= p_filter
->p_sys
;
326 var_DelCallback( p_filter
, FILTER_PREFIX
"color",
327 ballCallback
, p_sys
);
328 var_DelCallback( p_filter
, FILTER_PREFIX
"size",
329 ballCallback
, p_sys
);
330 var_DelCallback( p_filter
, FILTER_PREFIX
"speed",
331 ballCallback
, p_sys
);
332 var_DelCallback( p_filter
, FILTER_PREFIX
"edge-visible",
333 ballCallback
, p_sys
);
335 vlc_mutex_destroy( &p_sys
->lock
);
337 image_HandlerDelete( p_sys
->p_image
);
339 free( p_sys
->p_smooth
);
340 free( p_sys
->p_grad_x
);
341 free( p_sys
->p_grad_y
);
347 /*****************************************************************************
348 * Render: displays previously rendered output
349 *****************************************************************************
350 * This function send the currently rendered image to Distort image, waits
351 * until it is displayed and switch the two rendering buffers, preparing next
353 *****************************************************************************/
354 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
358 if( !p_pic
) return NULL
;
360 p_outpic
= filter_NewPicture( p_filter
);
363 picture_Release( p_pic
);
367 vlc_mutex_lock( &p_filter
->p_sys
->lock
);
368 FilterBall( p_filter
, p_pic
, p_outpic
);
369 vlc_mutex_unlock( &p_filter
->p_sys
->lock
);
371 return CopyInfoAndRelease( p_outpic
, p_pic
);
375 /*****************************************************************************
377 *****************************************************************************/
379 static void drawBall( filter_sys_t
*p_sys
, picture_t
*p_outpic
)
381 int x
= p_sys
->i_ball_x
;
382 int y
= p_sys
->i_ball_y
;
383 int size
= p_sys
->i_ballSize
;
385 const int i_width
= p_outpic
->p
[0].i_visible_pitch
;
386 const int i_height
= p_outpic
->p
[0].i_visible_lines
;
388 for( int j
= y
- size
; j
<= y
+ size
; j
++ )
390 bool b_skip
= ( x
- size
) % 2;
391 for( int i
= x
- size
; i
<= x
+ size
; i
++ )
393 /* Draw the pixel if it is inside the disk
394 and check we don't write out the frame. */
395 if( ( i
- x
) * ( i
- x
) + ( j
- y
) * ( j
- y
) <= size
* size
396 && i
>= 0 && i
< i_width
397 && j
>= 0 && j
< i_height
)
399 ( *p_sys
->drawingPixelFunction
)( p_sys
, p_outpic
,
400 colorList
[ p_sys
->ballColor
].comp1
,
401 colorList
[ p_sys
->ballColor
].comp2
,
402 colorList
[ p_sys
->ballColor
].comp3
,
411 static void drawPixelRGB24( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
412 uint8_t R
, uint8_t G
, uint8_t B
,
413 int x
, int y
, bool b_skip
)
416 VLC_UNUSED( b_skip
);
417 uint8_t *p_pixel
= p_outpic
->p
[0].p_pixels
418 + p_outpic
->p
[0].i_pitch
426 static void drawPixelI420( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
427 uint8_t Y
, uint8_t U
, uint8_t V
,
428 int x
, int y
, bool b_skip
)
431 *( p_outpic
->p
[0].p_pixels
+ p_outpic
->p
[0].i_pitch
* y
+ x
) = Y
;
434 *( p_outpic
->p
[2].p_pixels
+ p_outpic
->p
[2].i_pitch
435 * ( y
/ 2 ) + x
/ 2 ) = U
;
436 *( p_outpic
->p
[1].p_pixels
+ p_outpic
->p
[1].i_pitch
437 * ( y
/ 2 ) + x
/ 2 ) = V
;
442 static void drawPixelPacked( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
443 uint8_t Y
, uint8_t U
, uint8_t V
,
444 int x
, int y
, bool b_skip
)
446 uint8_t *p_pixel
= p_outpic
->p
[0].p_pixels
447 + p_outpic
->p
[0].i_pitch
* y
+ x
* 2;
448 *( p_pixel
+ p_sys
->i_y_offset
) = Y
;
451 *( p_pixel
+ p_sys
->i_u_offset
) = U
;
452 *( p_pixel
+ p_sys
->i_v_offset
) = V
;
457 /*****************************************************************************
459 *****************************************************************************
460 * Modify its value to set its norm to 1 and keep its direction.
461 *****************************************************************************/
462 static void NormalizeVector( float *vect_x
, float *vect_y
)
464 float norm
= sqrt( *vect_x
* *vect_x
+ *vect_y
* *vect_y
);
465 if( *vect_x
!= 0 || *vect_y
!= 0 )
473 /*****************************************************************************
474 * Gaussian Convolution
475 *****************************************************************************
476 * Gaussian convolution ( sigma == 1.4 )
478 * | 2 4 5 4 2 | | 2 4 4 4 2 |
479 * | 4 9 12 9 4 | | 4 8 12 8 4 |
480 * | 5 12 15 12 5 | ~ | 4 12 16 12 4 |
481 * | 4 9 12 9 4 | | 4 8 12 8 4 |
482 * | 2 4 5 4 2 | | 2 4 4 4 2 |
483 *****************************************************************************/
484 static void GaussianConvolution( picture_t
*p_inpic
, uint32_t *p_smooth
)
486 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
487 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
488 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
489 const int i_numLines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
492 for( y
= 2; y
< i_numLines
- 2; y
++ )
494 for( x
= 2; x
< i_src_visible
- 2; x
++ )
496 p_smooth
[y
*i_src_visible
+x
] = (uint32_t)(
498 ( p_inpix
[(y
-2)*i_src_pitch
+x
-2] )
499 + ((p_inpix
[(y
-2)*i_src_pitch
+x
-1]
500 + p_inpix
[(y
-2)*i_src_pitch
+x
]
501 + p_inpix
[(y
-2)*i_src_pitch
+x
+1])<<1 )
502 + ( p_inpix
[(y
-2)*i_src_pitch
+x
+2] )
504 + ((p_inpix
[(y
-1)*i_src_pitch
+x
-2]
505 + ( p_inpix
[(y
-1)*i_src_pitch
+x
-1]<<1 )
506 + ( p_inpix
[(y
-1)*i_src_pitch
+x
]*3 )
507 + ( p_inpix
[(y
-1)*i_src_pitch
+x
+1]<<1 )
508 + p_inpix
[(y
-1)*i_src_pitch
+x
+2]
510 + p_inpix
[y
*i_src_pitch
+x
-2]
511 + ( p_inpix
[y
*i_src_pitch
+x
-1]*3 )
512 + ( p_inpix
[y
*i_src_pitch
+x
]<<2 )
513 + ( p_inpix
[y
*i_src_pitch
+x
+1]*3 )
514 + p_inpix
[y
*i_src_pitch
+x
+2]
516 + p_inpix
[(y
+1)*i_src_pitch
+x
-2]
517 + ( p_inpix
[(y
+1)*i_src_pitch
+x
-1]<<1 )
518 + ( p_inpix
[(y
+1)*i_src_pitch
+x
]*3 )
519 + ( p_inpix
[(y
+1)*i_src_pitch
+x
+1]<<1 )
520 + p_inpix
[(y
+1)*i_src_pitch
+x
+2] )<<1 )
522 + ( p_inpix
[(y
+2)*i_src_pitch
+x
-2] )
523 + ((p_inpix
[(y
+2)*i_src_pitch
+x
-1]
524 + p_inpix
[(y
+2)*i_src_pitch
+x
]
525 + p_inpix
[(y
+2)*i_src_pitch
+x
+1])<<1 )
526 + ( p_inpix
[(y
+2)*i_src_pitch
+x
+2] )
533 /*****************************************************************************
534 * FilterBall: Augmented reality ball video filter
535 *****************************************************************************
536 * The edge detection part comes from gradient.c video filter module.
537 * The Canny edge detection algorithm is used :
538 * http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
539 * (well ... the implementation isn't really the canny algorithm ... but some
540 * ideas are the same)
541 *****************************************************************************/
542 static void FilterBall( filter_t
*p_filter
, picture_t
*p_inpic
,
543 picture_t
*p_outpic
)
546 filter_sys_t
*p_sys
= p_filter
->p_sys
;
552 picture_t
*p_converted
;
553 video_format_t fmt_comp
;
555 switch( p_filter
->fmt_in
.video
.i_chroma
)
557 case VLC_CODEC_RGB24
:
559 fmt_comp
.i_width
= p_filter
->fmt_in
.video
.i_width
;
560 fmt_comp
.i_height
= p_filter
->fmt_in
.video
.i_height
;
561 fmt_comp
.i_chroma
= VLC_FOURCC('G','R','E','Y');
562 fmt_comp
.i_visible_width
= fmt_comp
.i_width
;
563 fmt_comp
.i_visible_height
= fmt_comp
.i_height
;
565 p_converted
= image_Convert( p_filter
->p_sys
->p_image
, p_inpic
,
566 &(p_filter
->fmt_in
.video
),
574 p_converted
= p_inpic
;
578 const int i_numCols
= p_converted
->p
[0].i_visible_pitch
;
579 const int i_numLines
= p_converted
->p
[0].i_visible_lines
;
581 if( !p_filter
->p_sys
->p_smooth
)
582 p_filter
->p_sys
->p_smooth
=
583 (uint32_t *)malloc( i_numLines
* i_numCols
585 p_smooth
= p_filter
->p_sys
->p_smooth
;
587 if( !p_filter
->p_sys
->p_grad_x
)
588 p_filter
->p_sys
->p_grad_x
=
589 (int32_t *)malloc( i_numLines
* i_numCols
591 p_grad_x
= p_filter
->p_sys
->p_grad_x
;
593 if( !p_filter
->p_sys
->p_grad_y
)
594 p_filter
->p_sys
->p_grad_y
=
595 (int32_t *)malloc( i_numLines
* i_numCols
597 p_grad_y
= p_filter
->p_sys
->p_grad_y
;
599 if( !p_smooth
|| !p_grad_x
|| !p_grad_y
) return;
601 vlc_memcpy( p_outpic
->p
[0].p_pixels
, p_inpic
->p
[0].p_pixels
,
602 p_outpic
->p
[0].i_lines
* p_outpic
->p
[0].i_pitch
);
603 vlc_memcpy( p_outpic
->p
[1].p_pixels
, p_inpic
->p
[1].p_pixels
,
604 p_outpic
->p
[1].i_lines
* p_outpic
->p
[1].i_pitch
);
605 vlc_memcpy( p_outpic
->p
[2].p_pixels
, p_inpic
->p
[2].p_pixels
,
606 p_outpic
->p
[2].i_lines
* p_outpic
->p
[2].i_pitch
);
608 GaussianConvolution( p_converted
, p_smooth
);
610 /* Compute the picture Sobel gradient
612 | -2 0 2 | and | 0 0 0 |
613 | -1 0 1 | | -1 -2 -1 | */
615 for( y
= 1; y
< i_numLines
- 1; y
++ )
617 for( x
= 1; x
< i_numCols
- 1; x
++ )
620 p_grad_x
[ y
* i_numCols
+ x
] =
621 ( p_smooth
[(y
-1)*i_numCols
+x
-1]
622 - p_smooth
[(y
+1)*i_numCols
+x
-1] )
623 + ( ( p_smooth
[(y
-1)*i_numCols
+x
]
624 - p_smooth
[(y
+1)*i_numCols
+x
] ) <<1 )
625 + ( p_smooth
[(y
-1)*i_numCols
+x
+1]
626 - p_smooth
[(y
+1)*i_numCols
+x
+1] );
627 p_grad_y
[ y
* i_numCols
+ x
] =
628 ( p_smooth
[(y
-1)*i_numCols
+x
-1]
629 - p_smooth
[(y
-1)*i_numCols
+x
+1] )
630 + ( ( p_smooth
[y
*i_numCols
+x
-1]
631 - p_smooth
[y
*i_numCols
+x
+1] ) <<1 )
632 + ( p_smooth
[(y
+1)*i_numCols
+x
-1]
633 - p_smooth
[(y
+1)*i_numCols
+x
+1] );
637 if( p_sys
->b_edgeVisible
)
639 /* Display the edges. */
640 for( y
= 1; y
< i_numLines
- 1; y
++ )
642 for( x
= 1; x
< i_numCols
- 1; x
++ )
644 if( abs( p_grad_x
[ y
* i_numCols
+ x
] )
645 + abs( p_grad_y
[ y
* i_numCols
+ x
] )
646 > p_sys
->i_gradThresh
)
648 ( *p_sys
->drawingPixelFunction
)( p_sys
, p_outpic
,
649 colorList
[ WHITE
].comp1
,
650 colorList
[ WHITE
].comp2
,
651 colorList
[ WHITE
].comp3
,
660 float *pf_lastVect_x
= &p_sys
->f_lastVect_x
;
661 float *pf_lastVect_y
= &p_sys
->f_lastVect_y
;
663 float f_newVect_x
= 0;
664 float f_newVect_y
= 0;
665 float f_contVect_x
= 0;
666 float f_contVect_y
= 0;
668 int nb_collisions
= 0;
672 /* Test collisions for each pixel the ball will cover in its
674 for ( i_motion
= 0; i_motion
<= p_sys
->i_ballSpeed
&& !bounce
; i_motion
++ )
676 /* Compute next ball position */
677 x
= roundf( (float)p_sys
->i_ball_x
678 + *pf_lastVect_x
* (float)i_motion
);
679 y
= roundf( (float)p_sys
->i_ball_y
680 + *pf_lastVect_y
* (float)i_motion
);
682 for( int i
= x
- p_sys
->i_ballSize
; i
<= x
+ p_sys
->i_ballSize
; i
++ )
684 for( int j
= y
- p_sys
->i_ballSize
;
685 j
<= y
+ p_sys
->i_ballSize
; j
++ )
687 /* Test the pixel if it is inside the disk and check we don't
688 write out the frame. */
689 if( ( i
- x
) * ( i
- x
) + ( j
- y
) * ( j
- y
)
690 == p_sys
->i_ballSize
* p_sys
->i_ballSize
691 && j
<= i_numLines
- 1 && x
<= i_numCols
- 1
692 && j
>= 0 && i
>= 0 )
694 /* Test firstly the picture limit collisions. */
697 f_contVect_x
= x
- i
;
707 f_contVect_y
= y
- j
;
713 if( j
>= i_numLines
- 3 )
716 f_contVect_y
= y
- j
;
722 if( i
>= i_numCols
- 3 )
724 f_contVect_x
= x
- i
;
731 /* Test the collisions with edges. */
732 if( abs( p_grad_x
[ j
* i_numCols
+ i
] )
733 + abs( p_grad_y
[ j
* i_numCols
+ i
] )
734 > p_sys
->i_gradThresh
)
736 f_contVect_x
+= x
- i
;
737 f_contVect_y
+= y
- j
;
750 /* Compute normal vector. */
751 f_contVect_x
/= nb_collisions
;
752 f_contVect_y
/= nb_collisions
;
753 NormalizeVector( &f_contVect_x
, &f_contVect_y
);
755 /* Compute the new vector after the bounce. */
756 float cosinus
= *pf_lastVect_x
* f_contVect_x
757 + *pf_lastVect_y
* f_contVect_y
;
758 f_newVect_x
= *pf_lastVect_x
- 2 * cosinus
* f_contVect_x
;
759 f_newVect_y
= *pf_lastVect_y
- 2 * cosinus
* f_contVect_y
;
760 NormalizeVector( &f_newVect_x
, &f_newVect_y
);
762 *pf_lastVect_x
= f_newVect_x
;
763 *pf_lastVect_y
= f_newVect_y
;
768 /* Test if next pixel is outside the frame limits.
769 If it is the case, then the ball is blocked until it can move. */
770 x
= roundf( (float)x
+ *pf_lastVect_x
);
771 y
= roundf( (float)y
+ *pf_lastVect_y
);
772 if( x
- p_sys
->i_ballSize
< 2
773 || x
+ p_sys
->i_ballSize
> i_numCols
- 3
774 || y
- p_sys
->i_ballSize
< 2
775 || y
+ p_sys
->i_ballSize
> i_numLines
- 3 )
781 /* After a bouce, the first ball motion is always one pixel. */
782 i_motion
= p_sys
->i_ballSpeed
- 1;
787 /* Compute next ball position. */
788 p_sys
->i_ball_x
= roundf( (float)p_sys
->i_ball_x
+ *pf_lastVect_x
789 * (float)( p_sys
->i_ballSpeed
- i_motion
) );
790 p_sys
->i_ball_y
= roundf( p_sys
->i_ball_y
+ *pf_lastVect_y
791 * (float)( p_sys
->i_ballSpeed
- i_motion
) );
794 drawBall( p_sys
, p_outpic
);
796 switch( p_filter
->fmt_in
.video
.i_chroma
)
798 case VLC_CODEC_RGB24
:
800 picture_Release( p_converted
);
807 /*****************************************************************************
809 *****************************************************************************
810 * filter parameter modification callback
811 *****************************************************************************/
812 static int ballCallback( vlc_object_t
*p_this
, char const *psz_var
,
813 vlc_value_t oldval
, vlc_value_t newval
,
817 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
818 msg_Err( p_this
, "Test" );
820 vlc_mutex_lock( &p_sys
->lock
);
821 if( !strcmp( psz_var
, FILTER_PREFIX
"color" ) )
823 p_sys
->ballColor
= getBallColor( p_this
, newval
.psz_string
);
825 else if( !strcmp( psz_var
, FILTER_PREFIX
"size" ) )
827 p_sys
->i_ballSize
= newval
.i_int
;
829 else if( !strcmp( psz_var
, FILTER_PREFIX
"speed" ) )
831 p_sys
->i_ballSpeed
= newval
.i_int
;
833 else if( !strcmp( psz_var
, FILTER_PREFIX
"edge-visible" ) )
835 p_sys
->b_edgeVisible
= newval
.b_bool
;
837 else if( !strcmp( psz_var
, FILTER_PREFIX
"gradient-threshold" ) )
839 p_sys
->i_gradThresh
= newval
.i_int
;
841 vlc_mutex_unlock( &p_sys
->lock
);
847 /*****************************************************************************
849 *****************************************************************************
850 * Get and assign the ball color value
851 *****************************************************************************/
852 static int getBallColor( vlc_object_t
*p_this
, char const *psz_newval
)
855 if( !strcmp( psz_newval
, "red" ) )
857 else if( !strcmp( psz_newval
, "blue" ) )
859 else if( !strcmp( psz_newval
, "green" ) )
861 else if( !strcmp( psz_newval
, "white" ) )
865 msg_Err( p_this
, "no valid ball color provided (%s)", psz_newval
);