Remove legacy parameter from add_string()
[vlc/asuraparaju-public.git] / modules / video_filter / ball.c
blobda36f333763a4c23cc5b8f5e476491a5dc5b2695
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
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
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 /*****************************************************************************
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>
42 #include "vlc_filter.h"
43 #include "filter_picture.h"
44 #include "vlc_image.h"
46 enum { RED, GREEN, BLUE, WHITE };
48 typedef struct
50 uint8_t comp1;
51 uint8_t comp2;
52 uint8_t comp3;
53 }COLOR;
55 static COLOR colorList[4];
57 #define COLORS_RGB \
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;
67 #define COLORS_YUV \
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 /*****************************************************************************
79 * Local prototypes
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,
100 void * );
101 static int getBallColor( vlc_object_t *p_this, char const *psz_newval );
104 /*****************************************************************************
105 * Module descriptor
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 \
119 of pixels")
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") };
132 vlc_module_begin ()
133 set_description( N_("Ball video filter") )
134 set_shortname( N_( "Ball" ))
135 set_help(BALL_HELP)
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 )
158 vlc_module_end ()
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 *****************************************************************************/
172 struct filter_sys_t
174 vlc_mutex_t lock;
176 int ballColor;
178 image_handler_t *p_image;
180 /* Ball position */
181 int i_ball_x;
182 int i_ball_y;
184 int i_ballSpeed;
186 int i_ballSize;
188 bool b_edgeVisible;
190 /* Offsets for YUV packed chroma */
191 int i_y_offset;
192 int i_u_offset;
193 int i_v_offset;
195 /* Gradient values */
196 uint32_t *p_smooth;
197 int32_t *p_grad_x;
198 int32_t *p_grad_y;
200 /* Gradient threshold */
201 int i_gradThresh;
203 /* Motion vectors */
204 float f_lastVect_x;
205 float f_lastVect_y;
207 float f_newVect_x;
208 float f_newVect_y;
210 float f_contVect_x;
211 float f_contVect_y;
213 /* Pointer on drawing function */
214 void ( *drawingPixelFunction )( filter_sys_t *, picture_t *,
215 uint8_t, uint8_t, uint8_t,
216 int, int, bool );
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;
228 char *psz_method;
230 /* Allocate structure */
231 p_filter->p_sys = malloc( sizeof( filter_sys_t ) );
232 if( p_filter->p_sys == NULL )
233 return VLC_ENOMEM;
235 switch( p_filter->fmt_in.video.i_chroma )
237 case VLC_CODEC_I420:
238 case VLC_CODEC_J420:
239 p_filter->p_sys->drawingPixelFunction = drawPixelI420;
240 COLORS_YUV
241 break;
242 CASE_PACKED_YUV_422
243 p_filter->p_sys->drawingPixelFunction = drawPixelPacked;
244 COLORS_YUV
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 );
249 break;
250 case VLC_CODEC_RGB24:
251 p_filter->p_sys->drawingPixelFunction = drawPixelRGB24;
252 COLORS_RGB
253 break;
254 default:
255 msg_Err( p_filter, "Unsupported input chroma (%4.4s)",
256 (char*)&(p_filter->fmt_in.video.i_chroma) );
257 return VLC_EGENERIC;
260 p_filter->p_sys->p_image = image_HandlerCreate( p_filter );
261 if( p_filter->p_sys->p_image == NULL )
262 return VLC_EGENERIC;
264 p_filter->pf_video_filter = Filter;
266 config_ChainParse( p_filter, FILTER_PREFIX, ppsz_filter_options,
267 p_filter->p_cfg );
269 if( !(psz_method =
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;
277 else
278 p_filter->p_sys->ballColor = getBallColor( p_this, psz_method );
280 free( 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;
312 return VLC_SUCCESS;
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 );
343 free( p_sys );
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
352 * frame.
353 *****************************************************************************/
354 static picture_t *Filter( filter_t *p_filter, picture_t *p_pic )
356 picture_t *p_outpic;
358 if( !p_pic ) return NULL;
360 p_outpic = filter_NewPicture( p_filter );
361 if( !p_outpic )
363 picture_Release( p_pic );
364 return NULL;
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 /*****************************************************************************
376 * Drawing functions
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,
403 i, j, b_skip );
405 b_skip = !b_skip;
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 )
415 VLC_UNUSED( p_sys );
416 VLC_UNUSED( b_skip );
417 uint8_t *p_pixel = p_outpic->p[0].p_pixels
418 + p_outpic->p[0].i_pitch
419 * x + 3 * y;
420 *p_pixel = B;
421 *++p_pixel = G;
422 *++p_pixel = R;
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 )
430 VLC_UNUSED( p_sys );
431 *( p_outpic->p[0].p_pixels + p_outpic->p[0].i_pitch * y + x ) = Y;
432 if( !b_skip )
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;
449 if( !b_skip )
451 *( p_pixel + p_sys->i_u_offset ) = U;
452 *( p_pixel + p_sys->i_v_offset ) = V;
457 /*****************************************************************************
458 * Nomalize vector
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 )
467 *vect_x /= norm;
468 *vect_y /= norm;
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;
491 int x,y;
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)(
497 /* 2 rows up */
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] )
503 /* 1 row up */
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]
509 /* */
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]
515 /* 1 row down */
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 )
521 /* 2 rows down */
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] )
527 ) >> 6 /* 115 */;
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 )
545 int x, y;
546 filter_sys_t *p_sys = p_filter->p_sys;
548 uint32_t *p_smooth;
549 int32_t *p_grad_x;
550 int32_t *p_grad_y;
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:
558 CASE_PACKED_YUV_422
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),
567 &fmt_comp );
568 if( !p_converted )
569 return;
571 break;
573 default:
574 p_converted = p_inpic;
575 break;
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
584 * sizeof(uint32_t));
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
590 * sizeof(int32_t));
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
596 * sizeof(int32_t));
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
611 | -1 0 1 | | 1 2 1 |
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,
652 x, y, 0 );
658 int i_motion;
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;
670 bool bounce = false;
672 /* Test collisions for each pixel the ball will cover in its
673 motion. */
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. */
695 if( i <= 2 )
697 f_contVect_x = x - i;
698 f_contVect_y = 0;
699 x++;
700 bounce = true;
701 nb_collisions = 1;
702 goto endLoop;
704 if( j <= 2 )
706 f_contVect_x = 0;
707 f_contVect_y = y - j;
708 y++;
709 bounce = true;
710 nb_collisions = 1;
711 goto endLoop;
713 if( j >= i_numLines - 3 )
715 f_contVect_x = 0;
716 f_contVect_y = y - j;
717 y--;
718 bounce = true;
719 nb_collisions = 1;
720 goto endLoop;
722 if( i >= i_numCols - 3 )
724 f_contVect_x = x - i;
725 f_contVect_y = 0;
726 x--;
727 bounce = true;
728 nb_collisions = 1;
729 goto endLoop;
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;
738 nb_collisions++;
739 bounce = true;
746 endLoop:
748 if( bounce )
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;
765 p_sys->i_ball_x = x;
766 p_sys->i_ball_y = 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 )
777 *pf_lastVect_x = 0;
778 *pf_lastVect_y = 0;
780 else
781 /* After a bouce, the first ball motion is always one pixel. */
782 i_motion = p_sys->i_ballSpeed - 1;
784 else
785 i_motion = 0;
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 ) );
793 /* Draw the ball */
794 drawBall( p_sys, p_outpic );
796 switch( p_filter->fmt_in.video.i_chroma )
798 case VLC_CODEC_RGB24:
799 CASE_PACKED_YUV_422
800 picture_Release( p_converted );
801 default:
802 break;
807 /*****************************************************************************
808 * ballCallback
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,
814 void *p_data )
816 VLC_UNUSED(oldval);
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 );
843 return VLC_SUCCESS;
847 /*****************************************************************************
848 * getBallColor
849 *****************************************************************************
850 * Get and assign the ball color value
851 *****************************************************************************/
852 static int getBallColor( vlc_object_t *p_this, char const *psz_newval )
854 int ret;
855 if( !strcmp( psz_newval, "red" ) )
856 ret = RED;
857 else if( !strcmp( psz_newval, "blue" ) )
858 ret = BLUE;
859 else if( !strcmp( psz_newval, "green" ) )
860 ret = GREEN;
861 else if( !strcmp( psz_newval, "white" ) )
862 ret = WHITE;
863 else
865 msg_Err( p_this, "no valid ball color provided (%s)", psz_newval );
866 ret = RED;
868 return ret;