qt: playlist: use item title if available
[vlc.git] / modules / video_filter / ball.c
blob01a6b5a4e86c8ff6e6200274fbcb5e60dd7fab8f
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
9 * writen by:
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 /*****************************************************************************
30 * Preamble
31 *****************************************************************************/
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
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 };
48 #define COLORS_RGB \
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;
58 #define COLORS_YUV \
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 /*****************************************************************************
70 * Local prototypes
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,
93 void * );
94 static int getBallColor( vlc_object_t *p_this, char const *psz_newval );
97 /*****************************************************************************
98 * Module descriptor
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 " \
111 "of pixels")
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") };
124 vlc_module_begin ()
125 set_description( N_("Ball video filter") )
126 set_shortname( N_( "Ball" ))
127 set_help(BALL_HELP)
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 )
149 vlc_module_end ()
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 *****************************************************************************/
163 struct filter_sys_t
165 vlc_mutex_t lock;
167 int ballColor;
169 image_handler_t *p_image;
171 /* Ball position */
172 int i_ball_x;
173 int i_ball_y;
175 int i_ballSpeed;
177 int i_ballSize;
179 bool b_edgeVisible;
181 /* Offsets for YUV packed chroma */
182 int i_y_offset;
183 int i_u_offset;
184 int i_v_offset;
186 /* Gradient values */
187 uint32_t *p_smooth;
188 int32_t *p_grad_x;
189 int32_t *p_grad_y;
191 /* Gradient threshold */
192 int i_gradThresh;
194 /* Motion vectors */
195 float f_lastVect_x;
196 float f_lastVect_y;
198 float f_newVect_x;
199 float f_newVect_y;
201 float f_contVect_x;
202 float f_contVect_y;
204 /* Pointer on drawing function */
205 void ( *drawingPixelFunction )( filter_sys_t *, picture_t *,
206 uint8_t, uint8_t, uint8_t,
207 int, int, bool );
208 struct
210 uint8_t comp1;
211 uint8_t comp2;
212 uint8_t comp3;
213 } colorList[4];
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 )
223 char *psz_method;
225 /* Allocate structure */
226 filter_sys_t *p_sys = malloc( sizeof( filter_sys_t ) );
227 if( p_sys == NULL )
228 return VLC_ENOMEM;
229 p_filter->p_sys = p_sys;
231 switch( p_filter->fmt_in.video.i_chroma )
233 case VLC_CODEC_I420:
234 case VLC_CODEC_J420:
235 p_sys->drawingPixelFunction = drawPixelI420;
236 COLORS_YUV
237 break;
238 CASE_PACKED_YUV_422
239 p_sys->drawingPixelFunction = drawPixelPacked;
240 COLORS_YUV
241 GetPackedYuvOffsets( p_filter->fmt_in.video.i_chroma,
242 &p_sys->i_y_offset,
243 &p_sys->i_u_offset,
244 &p_sys->i_v_offset );
245 break;
246 case VLC_CODEC_RGB24:
247 p_sys->drawingPixelFunction = drawPixelRGB24;
248 COLORS_RGB
249 break;
250 default:
251 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
252 (char*)&(p_filter->fmt_in.video.i_chroma) );
253 return VLC_EGENERIC;
256 p_sys->p_image = image_HandlerCreate( p_filter );
257 if( p_sys->p_image == NULL )
258 return VLC_EGENERIC;
260 p_filter->ops = &Filter_ops;
262 config_ChainParse( p_filter, FILTER_PREFIX, ppsz_filter_options,
263 p_filter->p_cfg );
265 if( !(psz_method =
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;
273 else
274 p_sys->ballColor = getBallColor( VLC_OBJECT(p_filter), psz_method );
276 free( psz_method );
278 p_sys->i_ballSize =
279 var_CreateGetIntegerCommand( p_filter, FILTER_PREFIX "size" );
280 p_sys->i_ballSpeed =
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;
308 return VLC_SUCCESS;
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 );
336 free( p_sys );
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
345 * frame.
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 /*****************************************************************************
356 * Drawing functions
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,
383 i, j, b_skip );
385 b_skip = !b_skip;
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 )
395 VLC_UNUSED( p_sys );
396 VLC_UNUSED( b_skip );
397 uint8_t *p_pixel = p_outpic->p[0].p_pixels
398 + p_outpic->p[0].i_pitch
399 * x + 3 * y;
400 *p_pixel = B;
401 *++p_pixel = G;
402 *++p_pixel = R;
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 )
410 VLC_UNUSED( p_sys );
411 *( p_outpic->p[0].p_pixels + p_outpic->p[0].i_pitch * y + x ) = Y;
412 if( !b_skip )
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;
429 if( !b_skip )
431 *( p_pixel + p_sys->i_u_offset ) = U;
432 *( p_pixel + p_sys->i_v_offset ) = V;
437 /*****************************************************************************
438 * Nomalize vector
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 )
447 *vect_x /= norm;
448 *vect_y /= norm;
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)(
476 /* 2 rows up */
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] )
482 /* 1 row up */
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]
488 /* */
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]
494 /* 1 row down */
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 )
500 /* 2 rows down */
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] )
506 ) >> 6 /* 115 */;
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 )
524 int x, y;
525 filter_sys_t *p_sys = p_filter->p_sys;
527 uint32_t *p_smooth;
528 int32_t *p_grad_x;
529 int32_t *p_grad_y;
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:
537 CASE_PACKED_YUV_422
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),
546 &fmt_comp );
547 video_format_Clean( &fmt_comp );
548 if( !p_converted )
549 return;
551 break;
553 default:
554 p_converted = p_inpic;
555 break;
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 )
562 p_sys->p_smooth =
563 (uint32_t *)vlc_alloc( i_numLines * i_numCols,
564 sizeof(uint32_t));
565 p_smooth = p_sys->p_smooth;
567 if( !p_sys->p_grad_x )
568 p_sys->p_grad_x =
569 (int32_t *)vlc_alloc( i_numLines * i_numCols,
570 sizeof(int32_t));
571 p_grad_x = p_sys->p_grad_x;
573 if( !p_sys->p_grad_y )
574 p_sys->p_grad_y =
575 (int32_t *)vlc_alloc( i_numLines * i_numCols,
576 sizeof(int32_t));
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
591 | -1 0 1 | | 1 2 1 |
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,
632 col, line, 0 );
638 int i_motion;
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;
650 bool bounce = false;
652 /* Test collisions for each pixel the ball will cover in its
653 motion. */
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. */
675 if( i <= 2 )
677 f_contVect_x = x - i;
678 f_contVect_y = 0;
679 x++;
680 bounce = true;
681 nb_collisions = 1;
682 goto endLoop;
684 if( j <= 2 )
686 f_contVect_x = 0;
687 f_contVect_y = y - j;
688 y++;
689 bounce = true;
690 nb_collisions = 1;
691 goto endLoop;
693 if( j >= i_numLines - 3 )
695 f_contVect_x = 0;
696 f_contVect_y = y - j;
697 y--;
698 bounce = true;
699 nb_collisions = 1;
700 goto endLoop;
702 if( i >= i_numCols - 3 )
704 f_contVect_x = x - i;
705 f_contVect_y = 0;
706 x--;
707 bounce = true;
708 nb_collisions = 1;
709 goto endLoop;
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;
718 nb_collisions++;
719 bounce = true;
726 endLoop:
728 if( bounce )
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;
745 p_sys->i_ball_x = x;
746 p_sys->i_ball_y = 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 )
757 *pf_lastVect_x = 0;
758 *pf_lastVect_y = 0;
760 else
761 /* After a bouce, the first ball motion is always one pixel. */
762 i_motion = p_sys->i_ballSpeed - 1;
764 else
765 i_motion = 0;
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 ) );
773 /* Draw the ball */
774 drawBall( p_sys, p_outpic );
776 switch( p_filter->fmt_in.video.i_chroma )
778 case VLC_CODEC_RGB24:
779 CASE_PACKED_YUV_422
780 picture_Release( p_converted );
781 default:
782 break;
787 /*****************************************************************************
788 * ballCallback
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,
794 void *p_data )
796 VLC_UNUSED(oldval);
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 );
823 return VLC_SUCCESS;
827 /*****************************************************************************
828 * getBallColor
829 *****************************************************************************
830 * Get and assign the ball color value
831 *****************************************************************************/
832 static int getBallColor( vlc_object_t *p_this, char const *psz_newval )
834 int ret;
835 if( !strcmp( psz_newval, "red" ) )
836 ret = RED;
837 else if( !strcmp( psz_newval, "blue" ) )
838 ret = BLUE;
839 else if( !strcmp( psz_newval, "green" ) )
840 ret = GREEN;
841 else if( !strcmp( psz_newval, "white" ) )
842 ret = WHITE;
843 else
845 msg_Err( p_this, "no valid ball color provided (%s)", psz_newval );
846 ret = RED;
848 return ret;