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_filter->p_sys->colorList[RED].comp1 = 255; p_filter->p_sys->colorList[RED].comp2 = 0; \
50 p_filter->p_sys->colorList[RED].comp3 = 0; \
51 p_filter->p_sys->colorList[GREEN].comp1 = 0; p_filter->p_sys->colorList[GREEN].comp2 = 255; \
52 p_filter->p_sys->colorList[GREEN].comp3 = 0; \
53 p_filter->p_sys->colorList[BLUE].comp1 = 0; p_filter->p_sys->colorList[BLUE].comp2 = 0; \
54 p_filter->p_sys->colorList[BLUE].comp3 = 255; \
55 p_filter->p_sys->colorList[WHITE].comp1 = 255; p_filter->p_sys->colorList[WHITE].comp2 = 255; \
56 p_filter->p_sys->colorList[WHITE].comp3 = 255;
59 p_filter->p_sys->colorList[RED].comp1 = 82; p_filter->p_sys->colorList[RED].comp2 = 240; \
60 p_filter->p_sys->colorList[RED].comp3 = 90; \
61 p_filter->p_sys->colorList[GREEN].comp1 = 145; p_filter->p_sys->colorList[GREEN].comp2 = 34; \
62 p_filter->p_sys->colorList[GREEN].comp3 = 54 ; \
63 p_filter->p_sys->colorList[BLUE].comp1 = 41; p_filter->p_sys->colorList[BLUE].comp2 = 146; \
64 p_filter->p_sys->colorList[BLUE].comp3 = 240; \
65 p_filter->p_sys->colorList[WHITE].comp1 = 255; p_filter->p_sys->colorList[WHITE].comp2 = 128; \
66 p_filter->p_sys->colorList[WHITE].comp3 = 128;
69 /*****************************************************************************
71 *****************************************************************************/
72 static int Create ( vlc_object_t
* );
73 static void Destroy ( vlc_object_t
* );
75 static picture_t
*Filter( filter_t
*, picture_t
* );
77 static void drawBall( filter_sys_t
*p_sys
, picture_t
*p_outpic
);
78 static void drawPixelRGB24( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
79 uint8_t R
, uint8_t G
, uint8_t B
,
80 int x
, int y
, bool b_skip
);
81 static void drawPixelI420( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
82 uint8_t Y
, uint8_t U
, uint8_t V
,
83 int x
, int y
, bool b_skip
);
84 static void drawPixelPacked( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
85 uint8_t Y
, uint8_t U
, uint8_t V
,
86 int x
, int y
, bool b_skip
);
88 static void FilterBall( filter_t
*, picture_t
*, picture_t
* );
89 static int ballCallback( vlc_object_t
*, char const *,
90 vlc_value_t
, vlc_value_t
,
92 static int getBallColor( vlc_object_t
*p_this
, char const *psz_newval
);
95 /*****************************************************************************
97 *****************************************************************************/
98 #define BALL_COLOR_TEXT N_("Ball color")
100 #define EDGE_VISIBLE_TEXT N_("Edge visible")
101 #define EDGE_VISIBLE_LONGTEXT N_("Set edge visibility.")
103 #define BALL_SPEED_TEXT N_("Ball speed")
104 #define BALL_SPEED_LONGTEXT N_("Set ball speed, the displacement value \
105 in number of pixels by frame.")
107 #define BALL_SIZE_TEXT N_("Ball size")
108 #define BALL_SIZE_LONGTEXT N_("Set ball size giving its radius in number \
111 #define GRAD_THRESH_TEXT N_("Gradient threshold")
112 #define GRAD_THRESH_LONGTEXT N_("Set gradient threshold for edge computation.")
114 #define BALL_HELP N_("Augmented reality ball game")
116 #define FILTER_PREFIX "ball-"
118 static const char *const mode_list
[] = { "red", "green", "blue", "white" };
119 static const char *const mode_list_text
[] = { N_("Red"), N_("Green"),
120 N_("Blue"), N_("White") };
123 set_description( N_("Ball video filter") )
124 set_shortname( N_( "Ball" ))
126 set_capability( "video filter", 0 )
127 set_category( CAT_VIDEO
)
128 set_subcategory( SUBCAT_VIDEO_VFILTER
)
130 add_string( FILTER_PREFIX
"color", "red",
131 BALL_COLOR_TEXT
, BALL_COLOR_TEXT
, false )
132 change_string_list( mode_list
, mode_list_text
)
134 add_integer_with_range( FILTER_PREFIX
"speed", 4, 1, 15,
135 BALL_SPEED_TEXT
, BALL_SPEED_LONGTEXT
, false )
137 add_integer_with_range( FILTER_PREFIX
"size", 10, 5, 30,
138 BALL_SIZE_TEXT
, BALL_SIZE_LONGTEXT
, false )
140 add_integer_with_range( FILTER_PREFIX
"gradient-threshold", 40, 1, 200,
141 GRAD_THRESH_TEXT
, GRAD_THRESH_LONGTEXT
, false )
143 add_bool( FILTER_PREFIX
"edge-visible", true,
144 EDGE_VISIBLE_TEXT
, EDGE_VISIBLE_LONGTEXT
, true )
146 add_shortcut( "ball" )
147 set_callbacks( Create
, Destroy
)
150 static const char *const ppsz_filter_options
[] = {
151 "color", "speed", "size",
152 "gradient-threshold", "edge-visible", NULL
156 /*****************************************************************************
157 * filter_sys_t: Distort video output method descriptor
158 *****************************************************************************
159 * This structure is part of the video output thread descriptor.
160 * It describes the Distort specific properties of an output thread.
161 *****************************************************************************/
168 image_handler_t
*p_image
;
180 /* Offsets for YUV packed chroma */
185 /* Gradient values */
190 /* Gradient threshold */
203 /* Pointer on drawing function */
204 void ( *drawingPixelFunction
)( filter_sys_t
*, picture_t
*,
205 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( vlc_object_t
*p_this
)
223 filter_t
*p_filter
= (filter_t
*)p_this
;
226 /* Allocate structure */
227 p_filter
->p_sys
= malloc( sizeof( filter_sys_t
) );
228 if( p_filter
->p_sys
== NULL
)
231 switch( p_filter
->fmt_in
.video
.i_chroma
)
235 p_filter
->p_sys
->drawingPixelFunction
= drawPixelI420
;
239 p_filter
->p_sys
->drawingPixelFunction
= drawPixelPacked
;
241 GetPackedYuvOffsets( p_filter
->fmt_in
.video
.i_chroma
,
242 &p_filter
->p_sys
->i_y_offset
,
243 &p_filter
->p_sys
->i_u_offset
,
244 &p_filter
->p_sys
->i_v_offset
);
246 case VLC_CODEC_RGB24
:
247 p_filter
->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_filter
->p_sys
->p_image
= image_HandlerCreate( p_filter
);
257 if( p_filter
->p_sys
->p_image
== NULL
)
260 p_filter
->pf_video_filter
= Filter
;
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_filter
->p_sys
->ballColor
= RED
;
274 p_filter
->p_sys
->ballColor
= getBallColor( p_this
, psz_method
);
278 p_filter
->p_sys
->i_ballSize
=
279 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"size" );
280 p_filter
->p_sys
->i_ballSpeed
=
281 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"speed" );
282 p_filter
->p_sys
->b_edgeVisible
=
283 var_CreateGetBoolCommand( p_filter
, FILTER_PREFIX
"edge-visible" );
284 p_filter
->p_sys
->i_gradThresh
=
285 var_CreateGetIntegerCommand( p_filter
, FILTER_PREFIX
"gradient-threshold" );
287 vlc_mutex_init( &p_filter
->p_sys
->lock
);
289 var_AddCallback( p_filter
, FILTER_PREFIX
"color",
290 ballCallback
, p_filter
->p_sys
);
291 var_AddCallback( p_filter
, FILTER_PREFIX
"size",
292 ballCallback
, p_filter
->p_sys
);
293 var_AddCallback( p_filter
, FILTER_PREFIX
"speed",
294 ballCallback
, p_filter
->p_sys
);
295 var_AddCallback( p_filter
, FILTER_PREFIX
"edge-visible",
296 ballCallback
, p_filter
->p_sys
);
298 p_filter
->p_sys
->p_smooth
= NULL
;
299 p_filter
->p_sys
->p_grad_x
= NULL
;
300 p_filter
->p_sys
->p_grad_y
= NULL
;
302 p_filter
->p_sys
->i_ball_x
= 100;
303 p_filter
->p_sys
->i_ball_y
= 100;
305 p_filter
->p_sys
->f_lastVect_x
= 0;
306 p_filter
->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( vlc_object_t
*p_this
)
319 filter_t
*p_filter
= (filter_t
*)p_this
;
320 filter_sys_t
*p_sys
= p_filter
->p_sys
;
322 var_DelCallback( p_filter
, FILTER_PREFIX
"color",
323 ballCallback
, p_sys
);
324 var_DelCallback( p_filter
, FILTER_PREFIX
"size",
325 ballCallback
, p_sys
);
326 var_DelCallback( p_filter
, FILTER_PREFIX
"speed",
327 ballCallback
, p_sys
);
328 var_DelCallback( p_filter
, FILTER_PREFIX
"edge-visible",
329 ballCallback
, p_sys
);
331 vlc_mutex_destroy( &p_sys
->lock
);
333 image_HandlerDelete( p_sys
->p_image
);
335 free( p_sys
->p_smooth
);
336 free( p_sys
->p_grad_x
);
337 free( p_sys
->p_grad_y
);
343 /*****************************************************************************
344 * Render: displays previously rendered output
345 *****************************************************************************
346 * This function send the currently rendered image to Distort image, waits
347 * until it is displayed and switch the two rendering buffers, preparing next
349 *****************************************************************************/
350 static picture_t
*Filter( filter_t
*p_filter
, picture_t
*p_pic
)
354 if( !p_pic
) return NULL
;
356 p_outpic
= filter_NewPicture( p_filter
);
359 picture_Release( p_pic
);
363 vlc_mutex_lock( &p_filter
->p_sys
->lock
);
364 FilterBall( p_filter
, p_pic
, p_outpic
);
365 vlc_mutex_unlock( &p_filter
->p_sys
->lock
);
367 return CopyInfoAndRelease( p_outpic
, p_pic
);
371 /*****************************************************************************
373 *****************************************************************************/
375 static void drawBall( filter_sys_t
*p_sys
, picture_t
*p_outpic
)
377 int x
= p_sys
->i_ball_x
;
378 int y
= p_sys
->i_ball_y
;
379 int size
= p_sys
->i_ballSize
;
381 const int i_width
= p_outpic
->p
[0].i_visible_pitch
;
382 const int i_height
= p_outpic
->p
[0].i_visible_lines
;
384 for( int j
= y
- size
; j
<= y
+ size
; j
++ )
386 bool b_skip
= ( x
- size
) % 2;
387 for( int i
= x
- size
; i
<= x
+ size
; i
++ )
389 /* Draw the pixel if it is inside the disk
390 and check we don't write out the frame. */
391 if( ( i
- x
) * ( i
- x
) + ( j
- y
) * ( j
- y
) <= size
* size
392 && i
>= 0 && i
< i_width
393 && j
>= 0 && j
< i_height
)
395 ( *p_sys
->drawingPixelFunction
)( p_sys
, p_outpic
,
396 p_sys
->colorList
[ p_sys
->ballColor
].comp1
,
397 p_sys
->colorList
[ p_sys
->ballColor
].comp2
,
398 p_sys
->colorList
[ p_sys
->ballColor
].comp3
,
407 static void drawPixelRGB24( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
408 uint8_t R
, uint8_t G
, uint8_t B
,
409 int x
, int y
, bool b_skip
)
412 VLC_UNUSED( b_skip
);
413 uint8_t *p_pixel
= p_outpic
->p
[0].p_pixels
414 + p_outpic
->p
[0].i_pitch
422 static void drawPixelI420( 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
)
427 *( p_outpic
->p
[0].p_pixels
+ p_outpic
->p
[0].i_pitch
* y
+ x
) = Y
;
430 *( p_outpic
->p
[2].p_pixels
+ p_outpic
->p
[2].i_pitch
431 * ( y
/ 2 ) + x
/ 2 ) = U
;
432 *( p_outpic
->p
[1].p_pixels
+ p_outpic
->p
[1].i_pitch
433 * ( y
/ 2 ) + x
/ 2 ) = V
;
438 static void drawPixelPacked( filter_sys_t
*p_sys
, picture_t
*p_outpic
,
439 uint8_t Y
, uint8_t U
, uint8_t V
,
440 int x
, int y
, bool b_skip
)
442 uint8_t *p_pixel
= p_outpic
->p
[0].p_pixels
443 + p_outpic
->p
[0].i_pitch
* y
+ x
* 2;
444 *( p_pixel
+ p_sys
->i_y_offset
) = Y
;
447 *( p_pixel
+ p_sys
->i_u_offset
) = U
;
448 *( p_pixel
+ p_sys
->i_v_offset
) = V
;
453 /*****************************************************************************
455 *****************************************************************************
456 * Modify its value to set its norm to 1 and keep its direction.
457 *****************************************************************************/
458 static void NormalizeVector( float *vect_x
, float *vect_y
)
460 float norm
= sqrt( *vect_x
* *vect_x
+ *vect_y
* *vect_y
);
461 if( *vect_x
!= 0 || *vect_y
!= 0 )
469 /*****************************************************************************
470 * Gaussian Convolution
471 *****************************************************************************
472 * Gaussian convolution ( sigma == 1.4 )
474 * | 2 4 5 4 2 | | 2 4 4 4 2 |
475 * | 4 9 12 9 4 | | 4 8 12 8 4 |
476 * | 5 12 15 12 5 | ~ | 4 12 16 12 4 |
477 * | 4 9 12 9 4 | | 4 8 12 8 4 |
478 * | 2 4 5 4 2 | | 2 4 4 4 2 |
479 *****************************************************************************/
480 static void GaussianConvolution( picture_t
*p_inpic
, uint32_t *p_smooth
)
482 const uint8_t *p_inpix
= p_inpic
->p
[Y_PLANE
].p_pixels
;
483 const int i_src_pitch
= p_inpic
->p
[Y_PLANE
].i_pitch
;
484 const int i_src_visible
= p_inpic
->p
[Y_PLANE
].i_visible_pitch
;
485 const int i_numLines
= p_inpic
->p
[Y_PLANE
].i_visible_lines
;
487 for( int y
= 2; y
< i_numLines
- 2; y
++ )
489 for( int x
= 2; x
< i_src_visible
- 2; x
++ )
491 p_smooth
[y
*i_src_visible
+x
] = (uint32_t)(
493 ( p_inpix
[(y
-2)*i_src_pitch
+x
-2] )
494 + ((p_inpix
[(y
-2)*i_src_pitch
+x
-1]
495 + p_inpix
[(y
-2)*i_src_pitch
+x
]
496 + p_inpix
[(y
-2)*i_src_pitch
+x
+1])<<1 )
497 + ( p_inpix
[(y
-2)*i_src_pitch
+x
+2] )
499 + ((p_inpix
[(y
-1)*i_src_pitch
+x
-2]
500 + ( p_inpix
[(y
-1)*i_src_pitch
+x
-1]<<1 )
501 + ( p_inpix
[(y
-1)*i_src_pitch
+x
]*3 )
502 + ( p_inpix
[(y
-1)*i_src_pitch
+x
+1]<<1 )
503 + p_inpix
[(y
-1)*i_src_pitch
+x
+2]
505 + p_inpix
[y
*i_src_pitch
+x
-2]
506 + ( p_inpix
[y
*i_src_pitch
+x
-1]*3 )
507 + ( p_inpix
[y
*i_src_pitch
+x
]<<2 )
508 + ( p_inpix
[y
*i_src_pitch
+x
+1]*3 )
509 + p_inpix
[y
*i_src_pitch
+x
+2]
511 + p_inpix
[(y
+1)*i_src_pitch
+x
-2]
512 + ( p_inpix
[(y
+1)*i_src_pitch
+x
-1]<<1 )
513 + ( p_inpix
[(y
+1)*i_src_pitch
+x
]*3 )
514 + ( p_inpix
[(y
+1)*i_src_pitch
+x
+1]<<1 )
515 + p_inpix
[(y
+1)*i_src_pitch
+x
+2] )<<1 )
517 + ( p_inpix
[(y
+2)*i_src_pitch
+x
-2] )
518 + ((p_inpix
[(y
+2)*i_src_pitch
+x
-1]
519 + p_inpix
[(y
+2)*i_src_pitch
+x
]
520 + p_inpix
[(y
+2)*i_src_pitch
+x
+1])<<1 )
521 + ( p_inpix
[(y
+2)*i_src_pitch
+x
+2] )
528 /*****************************************************************************
529 * FilterBall: Augmented reality ball video filter
530 *****************************************************************************
531 * The edge detection part comes from gradient.c video filter module.
532 * The Canny edge detection algorithm is used :
533 * http://fourier.eng.hmc.edu/e161/lectures/canny/node1.html
534 * (well ... the implementation isn't really the canny algorithm ... but some
535 * ideas are the same)
536 *****************************************************************************/
537 static void FilterBall( filter_t
*p_filter
, picture_t
*p_inpic
,
538 picture_t
*p_outpic
)
541 filter_sys_t
*p_sys
= p_filter
->p_sys
;
547 picture_t
*p_converted
;
548 video_format_t fmt_comp
;
549 memset( &fmt_comp
, 0, sizeof(fmt_comp
) );
551 switch( p_filter
->fmt_in
.video
.i_chroma
)
553 case VLC_CODEC_RGB24
:
555 fmt_comp
.i_width
= p_filter
->fmt_in
.video
.i_width
;
556 fmt_comp
.i_height
= p_filter
->fmt_in
.video
.i_height
;
557 fmt_comp
.i_chroma
= VLC_FOURCC('G','R','E','Y');
558 fmt_comp
.i_visible_width
= fmt_comp
.i_width
;
559 fmt_comp
.i_visible_height
= fmt_comp
.i_height
;
561 p_converted
= image_Convert( p_filter
->p_sys
->p_image
, p_inpic
,
562 &(p_filter
->fmt_in
.video
),
570 p_converted
= p_inpic
;
574 const int i_numCols
= p_converted
->p
[0].i_visible_pitch
;
575 const int i_numLines
= p_converted
->p
[0].i_visible_lines
;
577 if( !p_filter
->p_sys
->p_smooth
)
578 p_filter
->p_sys
->p_smooth
=
579 (uint32_t *)vlc_alloc( i_numLines
* i_numCols
,
581 p_smooth
= p_filter
->p_sys
->p_smooth
;
583 if( !p_filter
->p_sys
->p_grad_x
)
584 p_filter
->p_sys
->p_grad_x
=
585 (int32_t *)vlc_alloc( i_numLines
* i_numCols
,
587 p_grad_x
= p_filter
->p_sys
->p_grad_x
;
589 if( !p_filter
->p_sys
->p_grad_y
)
590 p_filter
->p_sys
->p_grad_y
=
591 (int32_t *)vlc_alloc( i_numLines
* i_numCols
,
593 p_grad_y
= p_filter
->p_sys
->p_grad_y
;
595 if( !p_smooth
|| !p_grad_x
|| !p_grad_y
) return;
597 memcpy( p_outpic
->p
[0].p_pixels
, p_inpic
->p
[0].p_pixels
,
598 p_outpic
->p
[0].i_lines
* p_outpic
->p
[0].i_pitch
);
599 memcpy( p_outpic
->p
[1].p_pixels
, p_inpic
->p
[1].p_pixels
,
600 p_outpic
->p
[1].i_lines
* p_outpic
->p
[1].i_pitch
);
601 memcpy( p_outpic
->p
[2].p_pixels
, p_inpic
->p
[2].p_pixels
,
602 p_outpic
->p
[2].i_lines
* p_outpic
->p
[2].i_pitch
);
604 GaussianConvolution( p_converted
, p_smooth
);
606 /* Compute the picture Sobel gradient
608 | -2 0 2 | and | 0 0 0 |
609 | -1 0 1 | | -1 -2 -1 | */
611 for( int y
= 1; y
< i_numLines
- 1; y
++ )
613 for( int x
= 1; x
< i_numCols
- 1; x
++ )
616 p_grad_x
[ y
* i_numCols
+ x
] =
617 ( p_smooth
[(y
-1)*i_numCols
+x
-1]
618 - p_smooth
[(y
+1)*i_numCols
+x
-1] )
619 + ( ( p_smooth
[(y
-1)*i_numCols
+x
]
620 - p_smooth
[(y
+1)*i_numCols
+x
] ) <<1 )
621 + ( p_smooth
[(y
-1)*i_numCols
+x
+1]
622 - p_smooth
[(y
+1)*i_numCols
+x
+1] );
623 p_grad_y
[ y
* 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
*i_numCols
+x
-1]
627 - p_smooth
[y
*i_numCols
+x
+1] ) <<1 )
628 + ( p_smooth
[(y
+1)*i_numCols
+x
-1]
629 - p_smooth
[(y
+1)*i_numCols
+x
+1] );
633 if( p_sys
->b_edgeVisible
)
635 /* Display the edges. */
636 for( int y
= 1; y
< i_numLines
- 1; y
++ )
638 for( int x
= 1; x
< i_numCols
- 1; x
++ )
640 if( abs( p_grad_x
[ y
* i_numCols
+ x
] )
641 + abs( p_grad_y
[ y
* i_numCols
+ x
] )
642 > p_sys
->i_gradThresh
)
644 ( *p_sys
->drawingPixelFunction
)( p_sys
, p_outpic
,
645 p_filter
->p_sys
->colorList
[ WHITE
].comp1
,
646 p_filter
->p_sys
->colorList
[ WHITE
].comp2
,
647 p_filter
->p_sys
->colorList
[ WHITE
].comp3
,
656 float *pf_lastVect_x
= &p_sys
->f_lastVect_x
;
657 float *pf_lastVect_y
= &p_sys
->f_lastVect_y
;
659 float f_newVect_x
= 0;
660 float f_newVect_y
= 0;
661 float f_contVect_x
= 0;
662 float f_contVect_y
= 0;
664 int nb_collisions
= 0;
668 /* Test collisions for each pixel the ball will cover in its
670 for ( i_motion
= 0; i_motion
<= p_sys
->i_ballSpeed
&& !bounce
; i_motion
++ )
672 /* Compute next ball position */
673 x
= roundf( (float)p_sys
->i_ball_x
674 + *pf_lastVect_x
* (float)i_motion
);
675 y
= roundf( (float)p_sys
->i_ball_y
676 + *pf_lastVect_y
* (float)i_motion
);
678 for( int i
= x
- p_sys
->i_ballSize
; i
<= x
+ p_sys
->i_ballSize
; i
++ )
680 for( int j
= y
- p_sys
->i_ballSize
;
681 j
<= y
+ p_sys
->i_ballSize
; j
++ )
683 /* Test the pixel if it is inside the disk and check we don't
684 write out the frame. */
685 if( ( i
- x
) * ( i
- x
) + ( j
- y
) * ( j
- y
)
686 == p_sys
->i_ballSize
* p_sys
->i_ballSize
687 && j
<= i_numLines
- 1 && x
<= i_numCols
- 1
688 && j
>= 0 && i
>= 0 )
690 /* Test firstly the picture limit collisions. */
693 f_contVect_x
= x
- i
;
703 f_contVect_y
= y
- j
;
709 if( j
>= i_numLines
- 3 )
712 f_contVect_y
= y
- j
;
718 if( i
>= i_numCols
- 3 )
720 f_contVect_x
= x
- i
;
727 /* Test the collisions with edges. */
728 if( abs( p_grad_x
[ j
* i_numCols
+ i
] )
729 + abs( p_grad_y
[ j
* i_numCols
+ i
] )
730 > p_sys
->i_gradThresh
)
732 f_contVect_x
+= x
- i
;
733 f_contVect_y
+= y
- j
;
746 /* Compute normal vector. */
747 f_contVect_x
/= nb_collisions
;
748 f_contVect_y
/= nb_collisions
;
749 NormalizeVector( &f_contVect_x
, &f_contVect_y
);
751 /* Compute the new vector after the bounce. */
752 float cosinus
= *pf_lastVect_x
* f_contVect_x
753 + *pf_lastVect_y
* f_contVect_y
;
754 f_newVect_x
= *pf_lastVect_x
- 2 * cosinus
* f_contVect_x
;
755 f_newVect_y
= *pf_lastVect_y
- 2 * cosinus
* f_contVect_y
;
756 NormalizeVector( &f_newVect_x
, &f_newVect_y
);
758 *pf_lastVect_x
= f_newVect_x
;
759 *pf_lastVect_y
= f_newVect_y
;
764 /* Test if next pixel is outside the frame limits.
765 If it is the case, then the ball is blocked until it can move. */
766 x
= roundf( (float)x
+ *pf_lastVect_x
);
767 y
= roundf( (float)y
+ *pf_lastVect_y
);
768 if( x
- p_sys
->i_ballSize
< 2
769 || x
+ p_sys
->i_ballSize
> i_numCols
- 3
770 || y
- p_sys
->i_ballSize
< 2
771 || y
+ p_sys
->i_ballSize
> i_numLines
- 3 )
777 /* After a bouce, the first ball motion is always one pixel. */
778 i_motion
= p_sys
->i_ballSpeed
- 1;
783 /* Compute next ball position. */
784 p_sys
->i_ball_x
= roundf( (float)p_sys
->i_ball_x
+ *pf_lastVect_x
785 * (float)( p_sys
->i_ballSpeed
- i_motion
) );
786 p_sys
->i_ball_y
= roundf( p_sys
->i_ball_y
+ *pf_lastVect_y
787 * (float)( p_sys
->i_ballSpeed
- i_motion
) );
790 drawBall( p_sys
, p_outpic
);
792 switch( p_filter
->fmt_in
.video
.i_chroma
)
794 case VLC_CODEC_RGB24
:
796 picture_Release( p_converted
);
803 /*****************************************************************************
805 *****************************************************************************
806 * filter parameter modification callback
807 *****************************************************************************/
808 static int ballCallback( vlc_object_t
*p_this
, char const *psz_var
,
809 vlc_value_t oldval
, vlc_value_t newval
,
813 filter_sys_t
*p_sys
= (filter_sys_t
*)p_data
;
814 msg_Err( p_this
, "Test" );
816 vlc_mutex_lock( &p_sys
->lock
);
817 if( !strcmp( psz_var
, FILTER_PREFIX
"color" ) )
819 p_sys
->ballColor
= getBallColor( p_this
, newval
.psz_string
);
821 else if( !strcmp( psz_var
, FILTER_PREFIX
"size" ) )
823 p_sys
->i_ballSize
= newval
.i_int
;
825 else if( !strcmp( psz_var
, FILTER_PREFIX
"speed" ) )
827 p_sys
->i_ballSpeed
= newval
.i_int
;
829 else if( !strcmp( psz_var
, FILTER_PREFIX
"edge-visible" ) )
831 p_sys
->b_edgeVisible
= newval
.b_bool
;
833 else if( !strcmp( psz_var
, FILTER_PREFIX
"gradient-threshold" ) )
835 p_sys
->i_gradThresh
= newval
.i_int
;
837 vlc_mutex_unlock( &p_sys
->lock
);
843 /*****************************************************************************
845 *****************************************************************************
846 * Get and assign the ball color value
847 *****************************************************************************/
848 static int getBallColor( vlc_object_t
*p_this
, char const *psz_newval
)
851 if( !strcmp( psz_newval
, "red" ) )
853 else if( !strcmp( psz_newval
, "blue" ) )
855 else if( !strcmp( psz_newval
, "green" ) )
857 else if( !strcmp( psz_newval
, "white" ) )
861 msg_Err( p_this
, "no valid ball color provided (%s)", psz_newval
);