From 78522b2201295bc8d22078cdfb0e76a68f45114e Mon Sep 17 00:00:00 2001 From: Niels Elburg Date: Sun, 2 Jan 2005 21:39:20 +0000 Subject: [PATCH] added video boids effect git-svn-id: svn://code.dyne.org/veejay/trunk@111 eb8d1916-c9e9-0310-b8de-cf0c9472ead5 --- veejay-current/libvje/Makefile.am | 2 +- veejay-current/libvje/effects/blob.c | 2 +- veejay-current/libvje/effects/boids.c | 413 ++++++++++++++++++++++++++ veejay-current/libvje/effects/boids.h | 32 ++ veejay-current/libvje/internal.h | 12 +- veejay-current/libvje/vj-effect.c | 5 +- veejay-current/libvje/vj-effman.c | 4 + veejay-current/libvje/vje.h | 2 +- veejay-current/veejay/vj-global.h | 2 +- 9 files changed, 466 insertions(+), 8 deletions(-) create mode 100644 veejay-current/libvje/effects/boids.c create mode 100644 veejay-current/libvje/effects/boids.h diff --git a/veejay-current/libvje/Makefile.am b/veejay-current/libvje/Makefile.am index 59591961..56a3817c 100644 --- a/veejay-current/libvje/Makefile.am +++ b/veejay-current/libvje/Makefile.am @@ -35,7 +35,7 @@ libvje_la_SOURCES = vj-effect.c vj-effman.c effects/common.c \ effects/isolate.c transitions/vbar.c transitions/3bar.c effects/enhancemask.c effects/noiseadd.c \ effects/contrast.c effects/motionblur.c effects/sinoids.c effects/average.c \ effects/ripple.c effects/water.c effects/noisepencil.c effects/bathroom.c effects/slice.c \ - effects/crosspixel.c effects/cartonize.c effects/nervous.c effects/morphology.c effects/blob.c effects/ghost.c + effects/crosspixel.c effects/cartonize.c effects/nervous.c effects/morphology.c effects/blob.c effects/boids.c effects/ghost.c libvje_la_LDFLAGS = $(VJE_ALL_LIB_OPTS) \ diff --git a/veejay-current/libvje/effects/blob.c b/veejay-current/libvje/effects/blob.c index 2b1d9f5b..428b335a 100644 --- a/veejay-current/libvje/effects/blob.c +++ b/veejay-current/libvje/effects/blob.c @@ -205,7 +205,7 @@ static void blob_render_rect(int s, int width) } } -blob_func *blob_render(void) +static blob_func *blob_render(void) { if( blob_type_ == BLOB_RECT) return &blob_render_rect; diff --git a/veejay-current/libvje/effects/boids.c b/veejay-current/libvje/effects/boids.c new file mode 100644 index 00000000..b5d83dfd --- /dev/null +++ b/veejay-current/libvje/effects/boids.c @@ -0,0 +1,413 @@ +/* + * Linux VeeJay + * + * Copyright(C)2002 Niels Elburg + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License , or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 , USA. + */ + +/* Copyright (C) 2002-2003 W.P. van Paassen - peter@paassen.tmfweb.nl + + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + + blob , originally from the demo effect collection + extended to video boids. the boids are an implementation of + Craig Reynolds's BOIDS behavioral algorithm + (http://www.vergenet.net/~conrad/boids/pseudocode.html) + + p0: radius + p1: number of blobs + p2: speed + p3: shape (rect,circle) + p4: influence boids trying to fly towards centre of mass of neighbouring boids + p5: influence boids trying to keep a small distance away from other boids + p6: influence boids trying to match velocity with near boids + + added basic flock rules: + 1. + 2. + 3. + + added optional flock rules: + - limiting speed + +*/ + +#include +#include +#include +#include +#include "common.h" +#include "blob.h" + + +typedef struct +{ + short x; // x + short y; // y + double vx; // velocity x + double vy; // velocity y +} blob_t; + +#define DEFAULT_RADIUS 10 +#define DEFAULT_NUM 100 + +#define BLOB_RECT 0 +#define BLOB_CIRCLE 1 + +static blob_t *blobs_; +static uint8_t **blob_; +static uint8_t *blob_image_; +static int blob_ready_ = 0; +static int blob_radius_ = 16; +static int blob_dradius_ = 0; +static int blob_sradius_ = 0; +static int blob_num_ = 50; +static int blob_type_ = 1; + +vj_effect *boids_init(int w, int h) +{ + vj_effect *ve = (vj_effect *) vj_malloc(sizeof(vj_effect)); + ve->num_params = 7; + ve->defaults = (int *) vj_malloc(sizeof(int) * ve->num_params); /* default values */ + ve->limits[0] = (int *) vj_malloc(sizeof(int) * ve->num_params); /* min */ + ve->limits[1] = (int *) vj_malloc(sizeof(int) * ve->num_params); /* max */ + ve->limits[0][0] = 0; + ve->limits[1][0] = 360; // radius + ve->limits[0][1] = 2; + ve->limits[1][1] = 100; // num blobs + ve->limits[0][2] = 0; + ve->limits[1][2] = 1; // shape + ve->limits[0][3] = 0; + ve->limits[1][3] = 100; // m1 + ve->limits[0][4] = 0; + ve->limits[1][4] = 100; // m2 + ve->limits[0][5] = 0; + ve->limits[1][5] = 100; // m3 + ve->limits[0][6] = 1; + ve->limits[1][6] = 1000; + ve->defaults[0] = DEFAULT_RADIUS; + ve->defaults[1] = DEFAULT_NUM; + ve->defaults[2] = 2; + ve->defaults[3] = 1; + ve->defaults[4] = 0; + ve->defaults[5] = 0; + ve->defaults[6] = 1; + + ve->description = "Video Boids"; + ve->sub_format = 1; + ve->extra_frame = 0; + ve->has_user =0; + return ve; +} + +static void blob_home_position( int blob_id, int w, int h , double v[2] ) +{ + double theta = 360.0 / ( (double) blob_num_ ) * blob_id; + double rad = (theta / 180.0 ) * M_PI; + double cx = ( double )( w/2); + double cy = ( double )( h/2); + v[0] = cx + cos(rad) * (w/3); + v[1] = cy + sin(rad) * (h/3); +} + +static void blob_init_( blob_t *b , int blob_id, int w , int h) +{ + double v[2]; + + blob_home_position( blob_id,w,h,v ); + + b->x = v[0]; + b->y = v[1]; + b->vx = 0.01; + b->vy = 0.01; +} +// FIXME private +int boids_malloc(int w, int h) +{ + int j,i; + double frac; + int dist_sqrt; + + if(blob_radius_ <= 0) + return 0; + + blob_dradius_ = blob_radius_ * 2; + blob_sradius_ = blob_radius_ * blob_radius_; + + blob_ = (uint8_t**) vj_malloc(sizeof(uint8_t*) * blob_dradius_ ); + for(i = 0; i < blob_dradius_ ; i ++ ) + { + blob_[i] = (uint8_t*) vj_malloc(sizeof(uint8_t) * blob_dradius_ ); + if(!blob_[i]) return 0; + } + + blobs_ = (blob_t*) vj_malloc(sizeof(blob_t) * blob_num_ ); + if(!blobs_ ) return 0; + + blob_image_ = (uint8_t*) vj_malloc(sizeof(uint8_t) * w * h ); + if(!blob_image_) return 0; + + + for( i = -blob_radius_ ; i < blob_radius_ ; ++ i ) + { + for( j = -blob_radius_ ; j < blob_radius_ ; ++ j ) + { + dist_sqrt = i * i + j * j; + if( dist_sqrt < blob_sradius_ ) + { + frac = (double) (sqrt(dist_sqrt)) / (double) blob_sradius_; + blob_[i + blob_radius_][j + blob_radius_] = 0xff; + } + else + { + blob_[i + blob_radius_][j + blob_radius_ ] = 0x0; // was 0 + } + } + } + + for( i = 0; i < blob_num_ ; i ++ ) + { + blob_init_( blobs_ + i ,i, w , h ); + } + + memset( blob_image_ , 0 , w * h ); + + blob_ready_ = 1; + + return 1; +} + + +void boids_free() +{ + int i; + for (i = 0; i < blob_dradius_ ; i ++ ) + if( blob_[i] ) free( blob_[i] ); + if(blobs_) + free(blobs_); + if(blob_image_) + free(blob_image_); +} + +typedef void (*blob_func)(int s, int width); + +static void *blob_render_circle(int s, int width) +{ + int i,j; + void *v; + for( i = 0; i < blob_dradius_ ; ++ i ) + { + for( j = 0; j < blob_dradius_ ; ++ j) + { + if( blob_image_[ s + j ] + blob_[i][j] > 255 ) + blob_image_[s + j] = 0xff; + else + blob_image_[s + j] += blob_[i][j]; + } + s += width; + } + return v; +} + +static void *blob_render_rect(int s, int width) +{ + int i,j; + void *v; + for( i = 0; i < blob_dradius_ ; ++ i ) + { + for( j = 0; j < blob_dradius_ ; ++ j) + { + blob_image_[s + j] = 0xff; + } + s += width; + } + return v; +} + +static blob_func *blob_render(void) +{ + if( blob_type_ == BLOB_RECT) + return &blob_render_rect; + return &blob_render_circle; +} + + +// calculate center of mass +static void boid_rule1_( int boid_id, double v1[2] ) +{ + int i; + double v[2] = { 0.0, 0.0 }; + for( i = 0; i < blob_num_ ; i ++ ) + { + if( i != boid_id ) + { + v[0] += (double) blobs_[i].x; + v[1] += (double) blobs_[i].y; + } + } + v[0] = v[0] / ( (double) blob_num_ - 1 ); + v[1] = v[1] / ( (double) blob_num_ - 1 ); + v1[0] = (v[0] - ((double)blobs_[boid_id].x)) / 100.0; + v1[1] = (v[1] - ((double)blobs_[boid_id].y)) / 100.0; +} + + +// try to keep a small distance away from other blobs +static void boid_rule2_( int boid_id, double v1[2] ) +{ + double v[2] = {0.0 , 0.0}; + int i; + for( i = 0; i < blob_num_; i ++ ) + { + if( i != boid_id) + { + // find nearby blob + double d = ( blobs_[boid_id].x - blobs_[i].x ) * ( blobs_[boid_id].x - blobs_[i].x ) + + ( blobs_[boid_id].y - blobs_[i].y ) * ( blobs_[boid_id].y - blobs_[i].y ); + + if( d < blob_sradius_ ) + { + v[0] = v[0] - ((double) ( blobs_[boid_id].x - blobs_[i].x )); + v[1] = v[1] - ((double) ( blobs_[boid_id].y - blobs_[i].y )); + } + } + } + v1[0] = v[0]; + v1[1] = v[1]; +} + +// try to match velocity with near blobs +static void boid_rule3_( int boid_id, double v1[2] ) +{ + double v[2] = { 0.0, 0.0 }; + int i; + for( i = 0; i < blob_num_; i ++ ) + { + if( boid_id != i ) + { + v[0] = v[0] + blobs_[i].vx; + v[1] = v[1] + blobs_[i].vy; + } + } + v1[0] = v[0] /( (double)( blob_num_ -1 )); + v1[0] = ( v[0] - blobs_[boid_id].vx ) / 8; + v1[1] = v[1] /( (double)( blob_num_ -1 )); + v1[1] = ( v[1] - blobs_[boid_id].vy ) / 8; +} + +static void boid_rule4_( int boid_id, int vlim ) +{ + // speed limiter + if( blobs_[boid_id].vx > vlim ) + blobs_[boid_id].vx = ( blobs_[boid_id].vx / fabs( blobs_[boid_id].vx) ) * vlim; + if( blobs_[boid_id].vy > vlim ) + blobs_[boid_id].vy = ( blobs_[boid_id].vy / fabs( blobs_[boid_id].vy) ) * vlim; +} + +void boids_apply(VJFrame *frame, + int width, int height, int radius, int num, int shape, int m1, int m2, int m3, int speed ) +{ + const int len = frame->len; + uint8_t *srcY = frame->data[0]; + uint8_t *srcCb= frame->data[1]; + uint8_t *srcCr= frame->data[2]; + int s,i,j,k; + const double M1 = ( (m1==0? 0.0 : m1/100.0) ); + const double M2 = ( (m2==0? 0.0 : m2/100.0) ); + const double M3 = ( (m3==0? 0.0 : m3/100.0) ); + + blob_func f = blob_render(); + + blob_type_ = shape; + + if( radius != blob_radius_ || num != blob_num_ ) + { // reinitialize + blob_radius_ = radius; + blob_num_ = num; + boids_free(); + boids_malloc(width,height); + } + + // move boid to new positions + for( i = 0; i < blob_num_; i ++) + { + double v1[2],v2[2],v3[2]; + + boid_rule1_( i, v1 ); + boid_rule2_( i, v2 ); + boid_rule3_( i, v3 ); + + v1[0] *= M1; + v1[1] *= M1; + v2[0] *= M2; + v2[1] *= M2; + v3[0] *= M3; + v3[1] *= M3; + + blobs_[i].vx = blobs_[i].vx + v1[0] + v2[0] + v3[0]; + blobs_[i].vy = blobs_[i].vy + v1[1] + v2[1] + v3[1]; + + boid_rule4_( i, speed * speed ); + + blobs_[i].x = blobs_[i].x + (short) blobs_[i].vx; + blobs_[i].y = blobs_[i].y + (short) blobs_[i].vy; + + } + + // fill blob + for( k = 0; k < blob_num_ ; k ++ ) + { + if( (blobs_[k].x > 0) && + (blobs_[k].x < (width - blob_dradius_)) && + (blobs_[k].y > 0) && + (blobs_[k].y < (height - blob_dradius_)) ) + { + s = blobs_[k].x + blobs_[k].y * width; + f(s,width); + } + else + { + blob_init_( blobs_ + k,k,width ,height ); + } + } + + // project blob onto video frame + for(i = 0; i < len ; i ++ ) + { + if( blob_image_[i] == 0x0 ) + { + srcY[i] = 16; + srcCb[i] = 128; + srcCr[i] = 128; + } + blob_image_[i] = 0x0; + } +} diff --git a/veejay-current/libvje/effects/boids.h b/veejay-current/libvje/effects/boids.h new file mode 100644 index 00000000..ff70f65e --- /dev/null +++ b/veejay-current/libvje/effects/boids.h @@ -0,0 +1,32 @@ +/* + * Linux VeeJay + * + * Copyright(C)2002 Niels Elburg + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License , or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307 , USA. + */ + +#ifndef BOIDS_H +#define BOIDS_H +#include +#include +#include + +vj_effect *boids_init(int w, int h); +void boids_apply( VJFrame *frame, int width, int height, int p0,int p1, int p2, int p3, int p4, int p5, int p6); +int boids_malloc( int w, int h ); +void boids_free(void); + +#endif diff --git a/veejay-current/libvje/internal.h b/veejay-current/libvje/internal.h index 56815a0f..f705f7ca 100644 --- a/veejay-current/libvje/internal.h +++ b/veejay-current/libvje/internal.h @@ -178,12 +178,14 @@ enum { VJ_IMAGE_EFFECT_NERVOUS = 162, VJ_IMAGE_EFFECT_MORPHOLOGY = 163, VJ_IMAGE_EFFECT_VIDBLOB = 164, - VJ_IMAGE_EFFECT_GHOST = 165, - VJ_IMAGE_EFFECT_DUMMY = 100, + VJ_IMAGE_EFFECT_VIDBOIDS = 165, + VJ_IMAGE_EFFECT_GHOST = 166, + + VJ_IMAGE_EFFECT_DUMMY = 100, }; #define VJ_IMAGE_EFFECT_MIN 100 -#define VJ_IMAGE_EFFECT_MAX 166 +#define VJ_IMAGE_EFFECT_MAX 167 #define VJ_VIDEO_EFFECT_MIN 200 #define VJ_VIDEO_EFFECT_MAX 236 @@ -475,6 +477,10 @@ extern void morphology_apply( VJFrame *frame, int w, int h, int t, int v, int p extern void blob_apply( VJFrame *frame, int w, int h, int p0,int p1, int p2, int p3); +extern void boids_apply( VJFrame *frame, int w, int h, int p0,int p1, int p2, int p3, int p4, int p5, int p6 +); + + extern void ghost_apply(VJFrame *frame, int w, int h, int o ); #endif diff --git a/veejay-current/libvje/vj-effect.c b/veejay-current/libvje/vj-effect.c index 1f0e581f..b4cb0685 100644 --- a/veejay-current/libvje/vj-effect.c +++ b/veejay-current/libvje/vj-effect.c @@ -128,6 +128,7 @@ #include "effects/morphology.h" #include "effects/blob.h" #include "effects/ghost.h" +#include "effects/boids.h" static struct { @@ -166,6 +167,7 @@ static struct { nervous_malloc, nervous_free, VJ_IMAGE_EFFECT_NERVOUS }, { morphology_malloc, morphology_free, VJ_IMAGE_EFFECT_MORPHOLOGY }, { blob_malloc, blob_free, VJ_IMAGE_EFFECT_VIDBLOB }, +{ boids_malloc, boids_free, VJ_IMAGE_EFFECT_VIDBOIDS }, { ghost_malloc, ghost_free, VJ_IMAGE_EFFECT_GHOST }, { NULL , NULL ,0 }, }; @@ -444,7 +446,8 @@ void vj_effect_initialize(int width, int height) vj_effects[i + 62] = nervous_init(width,height); vj_effects[i + 63] = morphology_init(width,height); vj_effects[i + 64] = blob_init(width,height); - vj_effects[i + 65] = ghost_init(width,height); + vj_effects[i + 65] = boids_init(width,height); + vj_effects[i + 66] = ghost_init(width,height); max_width = width; max_height = height; diff --git a/veejay-current/libvje/vj-effman.c b/veejay-current/libvje/vj-effman.c index 8f96f87a..157df059 100644 --- a/veejay-current/libvje/vj-effman.c +++ b/veejay-current/libvje/vj-effman.c @@ -163,6 +163,10 @@ void vj_effman_apply_image_effect( blob_apply( frames[0],frameinfo->width,frameinfo->height, arg[0],arg[1],arg[2],arg[3] ); break; + case VJ_IMAGE_EFFECT_VIDBOIDS: + boids_apply( frames[0],frameinfo->width,frameinfo->height, + arg[0],arg[1],arg[2],arg[3],arg[4],arg[5],arg[6] ); + break; case VJ_IMAGE_EFFECT_GHOST: ghost_apply( frames[0], frameinfo->width,frameinfo->height,arg[0]); break; diff --git a/veejay-current/libvje/vje.h b/veejay-current/libvje/vje.h index a02c56e4..44592fe2 100644 --- a/veejay-current/libvje/vje.h +++ b/veejay-current/libvje/vje.h @@ -25,7 +25,7 @@ #include #include -#define MAX_EFFECTS 102 +#define MAX_EFFECTS 103 // keyframe-able parameter sets diff --git a/veejay-current/veejay/vj-global.h b/veejay-current/veejay/vj-global.h index 9ddbfc40..ed870c75 100644 --- a/veejay-current/veejay/vj-global.h +++ b/veejay-current/veejay/vj-global.h @@ -67,7 +67,7 @@ enum { #define EDIT_COPY 103 #define EDIT_CROP 104 #define EDIT_DEL 105 -#define MAX_EFFECTS 102 +#define MAX_EFFECTS 103 #define MESSAGE_SIZE 1024 /* enough for my needs */ #define EL_MIN_BUF (65535 * 4) #define XMLTAG_BUNDLE_FILE "ACTIONFILE"