diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..5734a4e --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +BreakBeforeBraces: Allman +AllowShortFunctionsOnASingleLine: None diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5dc9d59 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,38 @@ +root = true + +[*] +# please only ever use utf-8 +charset = utf-8 + +; C and friends +[**.{c,cpp,h,hh,m,mm}] +# indent 4 spaces, BSD-style +indent_style = space +indent_size = 4 +indent_brace_style = BSD + +## let git handle proper EOL +#end_of_line = lf + +trim_trailing_whitespace = true +insert_final_newline = true + +max_line_length = 80 + +#continuation_indent_size = 4 +spaces_around_operators = true + +; applies only to Makefiles +[makefile] +indent_style = tab +tab_width = 4 +[**.am] +indent_style = tab +tab_width = 4 + +[**.tcl] +indent_style = space +indent_size = 4 +#continuation_indent_size = 8 +#curly_bracket_next_line = false + diff --git a/.github/actions/setup-pd/action.yml b/.github/actions/setup-pd/action.yml new file mode 100644 index 0000000..c79b6aa --- /dev/null +++ b/.github/actions/setup-pd/action.yml @@ -0,0 +1,17 @@ +name: Setup Pure Data +description: Checkout code and setup Pure Data dependencies + +runs: + using: composite + steps: + - name: get pdlibbuilder + shell: bash + run: | + git submodule init + git submodule update + + - name: get pd + uses: actions/checkout@v6 + with: + repository: pure-data/pure-data + path: pure-data diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..0b726ea --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,83 @@ +name: Cross-Platform Compile +description: Compiles on multiple platforms and publishes to deken when tags are pushed + +on: + workflow_dispatch: + + push: + branches: + - main + paths: + - "include/**" + - "src/**" + - "Makefile" + - "config.sh" + + tags: + - 'v*' + + pull_request: + paths: + - "include/**" + - "src/**" + - "Makefile" + - "config.sh" + +jobs: + build: + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + + runs-on: ${{ matrix.os }} + + defaults: + run: + shell: bash + + env: + PDVERSION: pd-0.56-2 + + steps: + - uses: actions/checkout@v6 + + # ---- platform-specific setup ---- + - name: setup pd (unix) + if: matrix.os != 'windows-latest' + uses: ./.github/actions/setup-pd + + - name: install mac deps + if: matrix.os == 'macos-latest' + run: brew install automake autoconf libtool + + - name: setup windows deps + if: matrix.os == 'windows-latest' + run: | + echo "local_short_commands=true" >> $GITHUB_ENV + git submodule init && git submodule update + curl -O "http://msp.ucsd.edu/Software/$PDVERSION.msw.zip" + unzip "$PDVERSION.msw.zip" + + # ---- build ---- + - name: configure + run: bash config.sh + + - name: make (unix) + if: matrix.os != 'windows-latest' + run: make PDINCLUDEDIR=pure-data/src + + - name: make (windows) + if: matrix.os == 'windows-latest' + run: make pdbinpath="$PDVERSION/bin" PDINCLUDEDIR="$PDVERSION/src" CFLAGS=-march=x86-64 + + # ---- package ---- + - name: package library + run: | + bash scripts/package_lib.sh "${{ matrix.os }}" + + - name: upload artifact + uses: actions/upload-artifact@v6 + with: + name: "boids-${{ github.ref_name }}-${{ matrix.os }}-build" + path: "${{ matrix.os }}" + if-no-files-found: error diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f5dd675 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.pd_linux +*.o +compile_commands.json +.cache/ diff --git a/Makefile b/Makefile index 78a7435..6dfd6e4 100644 --- a/Makefile +++ b/Makefile @@ -2,25 +2,20 @@ # Needs Makefile.pdlibbuilder as helper makefile for platform-dependent build # settings and rules. + # library name lib.name = boids - +lib.setup.sources = src/boids.c # input source file (class name == source file basename) -class.sources = \ - boids2d.c \ - boids3d.c \ - $(empty) +class.sources = src/boids.c +common.sources = src/boid_params.c src/vec.c # all extra files to be included in binary distribution of the library -datafiles = \ - boids-meta.pd \ - boids2d-help.pd \ - boids3d-help.pd \ - README.txt LICENSE.txt +datafiles = boids-meta.pd README.txt LICENSE.txt $(wildcard boids/*.pd) $(wildcard help/*.pd) + +datadirs = examples boids -datadirs = \ - examples \ - $(empty) +cflags = -O0 -g3 -fno-inline -fno-omit-frame-pointer -Wall -Wextra -Wpedantic # include Makefile.pdlibbuilder from submodule directory 'pd-lib-builder' PDLIBBUILDER_DIR=pd-lib-builder/ diff --git a/boids/boids-params.pd b/boids/boids-params.pd new file mode 100644 index 0000000..43d152c --- /dev/null +++ b/boids/boids-params.pd @@ -0,0 +1,288 @@ +#N canvas 74 74 1255 607 12; +#X text 487 26 Boids Parameters; +#N canvas 112 25 779 393 glue 0; +#X obj 48 57 r \$1-number; +#X obj 48 107 s \$1-boids-params; +#X obj 48 82 list prepend number; +#X obj 219 57 r \$1-neighbors; +#X obj 219 107 s \$1-boids-params; +#X obj 219 82 list prepend neighbors; +#X obj 387 57 r \$1-inertia; +#X obj 387 107 s \$1-boids-params; +#X obj 387 82 list prepend inertia; +#X obj 558 57 r \$1-speed; +#X obj 558 107 s \$1-boids-params; +#X obj 558 82 list prepend speed; +#X obj 47 135 r \$1-maxspeed; +#X obj 47 185 s \$1-boids-params; +#X obj 47 160 list prepend maxspeed; +#X obj 218 135 r \$1-minspeed; +#X obj 218 185 s \$1-boids-params; +#X obj 218 160 list prepend minspeed; +#X obj 388 140 r \$1-accel; +#X obj 388 190 s \$1-boids-params; +#X obj 388 165 list prepend accel; +#X obj 559 140 r \$1-match; +#X obj 559 190 s \$1-boids-params; +#X obj 559 165 list prepend match; +#X obj 46 218 r \$1-avoid; +#X obj 46 268 s \$1-boids-params; +#X obj 46 243 list prepend avoid; +#X obj 217 218 r \$1-repel; +#X obj 217 268 s \$1-boids-params; +#X obj 217 243 list prepend repel; +#X obj 385 218 r \$1-edgedist; +#X obj 385 268 s \$1-boids-params; +#X obj 385 243 list prepend edgedist; +#X obj 556 218 r \$1-prefdist; +#X obj 556 268 s \$1-boids-params; +#X obj 556 243 list prepend prefdist; +#X obj 45 296 r \$1-center; +#X obj 45 346 s \$1-boids-params; +#X obj 45 321 list prepend center; +#X obj 216 296 r \$1-attract; +#X obj 216 346 s \$1-boids-params; +#X obj 216 321 list prepend attract; +#X text 55 22 prepend the parameter name to the parameter values and send them to the global receiver, f 88; +#N canvas 192 66 1405 689 flyrect-dimensions 0; +#X obj 352 423 * -1; +#X obj 352 448 pack; +#X obj 55 109 r \$1-dimensions; +#X msg 353 243 symbol flyrect; +#X obj 353 268 text search \$1-parameters; +#X obj 353 293 sel -1; +#X msg 353 318 1; +#X obj 392 317 text get \$1-parameters; +#X obj 352 374 abs; +#X obj 124 523 list store, f 16; +#X obj 124 442 until; +#X obj 124 469 list; +#X msg 124 494 append \$1 \$2; +#X obj 78 417 t b f; +#X obj 124 549 t a b; +#X obj 124 574 list prepend flyrect; +#X obj 83 639 s \$1-boids-params; +#X obj 55 166 t f f b; +#X obj 392 343 list split 1; +#X obj 432 368 list split 1; +#X obj 55 606 list prepend dimensions; +#X text 176 548 -bound \, +bound \, -bound \, +bound \, etc; +#X text 32 60 bounds is interpreted as a pair -bound \, +bound per dimension to build the flying rectangle (or cube \, etc) \, so they are interlinked with dimensions, f 77; +#X text 184 16 Special treatment for dimensions and bounds (flyrect); +#X listbox 106 138 20 0 0 0 - - - 0; +#X listbox 354 479 20 0 0 0 - - - 0; +#X obj 134 268 text search \$1-parameters; +#X obj 134 293 sel -1; +#X obj 173 317 text get \$1-parameters; +#X obj 173 343 list split 1; +#X msg 134 243 symbol dimensions; +#X msg 134 318 2; +#X obj 571 244 list split 1; +#X obj 339 119 r \$1-bounds; +#X obj 353 350 t f; +#X obj 353 215 sel 0; +#X obj 353 190 f 0; +#X obj 352 398 t f f f; +#X obj 398 452 s \$1-bounds-set; +#X obj 55 138 max 1; +#X obj 137 391 s \$1-dimensions; +#X obj 337 143 t b f; +#X msg 407 427 set \$1; +#X floatatom 399 182 5 0 0 0 - - - 0; +#X floatatom 508 406 5 0 0 0 - - - 0; +#X obj 571 219 r \$1-flyrect-set; +#X obj 571 269 abs; +#X obj 571 294 s \$1-bounds-set; +#X connect 0 0 1 0; +#X connect 1 0 11 1; +#X connect 1 0 25 0; +#X connect 2 0 39 0; +#X connect 3 0 4 0; +#X connect 4 0 5 0; +#X connect 5 0 6 0; +#X connect 5 1 7 0; +#X connect 6 0 34 0; +#X connect 7 0 18 0; +#X connect 8 0 37 0; +#X connect 9 0 14 0; +#X connect 10 0 11 0; +#X connect 11 0 12 0; +#X connect 12 0 9 0; +#X connect 13 0 9 0; +#X connect 13 1 10 0; +#X connect 14 0 15 0; +#X connect 14 1 9 1; +#X connect 15 0 16 0; +#X connect 17 0 20 0; +#X connect 17 1 13 0; +#X connect 17 2 36 0; +#X connect 18 1 19 0; +#X connect 19 0 34 0; +#X connect 19 0 44 0; +#X connect 20 0 16 0; +#X connect 26 0 27 0; +#X connect 27 0 31 0; +#X connect 27 1 28 0; +#X connect 28 0 29 0; +#X connect 29 1 40 0; +#X connect 30 0 26 0; +#X connect 31 0 40 0; +#X connect 32 0 46 0; +#X connect 33 0 41 0; +#X connect 34 0 8 0; +#X connect 35 0 3 0; +#X connect 35 1 34 0; +#X connect 36 0 35 0; +#X connect 37 0 0 0; +#X connect 37 1 1 1; +#X connect 37 2 42 0; +#X connect 39 0 17 0; +#X connect 39 0 24 0; +#X connect 41 0 30 0; +#X connect 41 1 36 1; +#X connect 41 1 43 0; +#X connect 42 0 38 0; +#X connect 45 0 32 0; +#X connect 46 0 47 0; +#X restore 476 327 pd flyrect-dimensions; +#X connect 0 0 2 0; +#X connect 2 0 1 0; +#X connect 3 0 5 0; +#X connect 5 0 4 0; +#X connect 6 0 8 0; +#X connect 8 0 7 0; +#X connect 9 0 11 0; +#X connect 11 0 10 0; +#X connect 12 0 14 0; +#X connect 14 0 13 0; +#X connect 15 0 17 0; +#X connect 17 0 16 0; +#X connect 18 0 20 0; +#X connect 20 0 19 0; +#X connect 21 0 23 0; +#X connect 23 0 22 0; +#X connect 24 0 26 0; +#X connect 26 0 25 0; +#X connect 27 0 29 0; +#X connect 29 0 28 0; +#X connect 30 0 32 0; +#X connect 32 0 31 0; +#X connect 33 0 35 0; +#X connect 35 0 34 0; +#X connect 36 0 38 0; +#X connect 38 0 37 0; +#X connect 39 0 41 0; +#X connect 41 0 40 0; +#X restore 841 95 pd glue; +#X obj 104 451 r \$1-boids-params; +#X obj 105 479 outlet; +#N canvas 0 0 577 425 defaults 0; +#X obj 108 113 list prepend \$1; +#X obj 112 82 r \$1-defaults; +#X msg 103 139 \; \$1-dimensions-set 2 \; \$1-number-set 16 \; \$1-neighbors-set 4 \; \$1-maxspeed-set 1.5 \; \$1-minspeed-set 1.2 \; \$1-center-set 1.2 \; \$1-attract-set 1.25 \; \$1-match-set 0.3 \; \$1-avoid-set 3.5 \; \$1-repel-set 3.5 \; \$1-edgedist-set 3 \; \$1-speed-set 3 \; \$1-inertia-set 4.5 \; \$1-accel-set 2.5 \; \$1-prefdist-set 1.5 \; \$1-bounds-set 1 \;, f 36; +#X text 62 27 keep a list of default parameter values reflecting the internal initial state of the object; +#X connect 0 0 2 0; +#X connect 1 0 0 0; +#X restore 841 128 pd defaults; +#N canvas 133 208 1066 594 storage 0; +#X obj 646 299 savestate; +#X obj 68 187 r \$1-boids-params; +#X obj 65 239 list split 1; +#X obj 73 339 text search \$1-parameters; +#X obj 135 446 text set \$1-parameters 0 1; +#X obj 73 368 sel -1; +#X obj 139 392 t b f; +#X obj 731 337 text sequence \$1-parameters; +#X msg 732 309 line 0 \, auto; +#X obj 66 214 t a a; +#X obj 71 408 list; +#X obj 72 445 t a b; +#X msg 100 481 1e+10; +#X obj 66 506 text set \$1-parameters; +#X obj 137 421 list; +#X obj 535 208 text sequence \$1-parameters; +#X msg 536 180 line 0 \, auto; +#X obj 538 150 r \$1-output; +#X obj 532 355 t a a; +#X obj 589 420 list split 1; +#X obj 532 389 list split 1; +#X obj 571 485 s; +#X obj 589 445 makefilename \$1-%s-set; +#X text 533 96 this updates the number boxes with the stored parameters in the text (and subsequently outputs the parameters); +#X text 636 257 this saves the parameter text when saving the main patch (outputs it on load); +#X text 28 288 if the param is already in the text \, update it. Otherwise \, we create a new line for that parameter, f 51; +#X text 30 87 store the parameters on the text on a dictionary: a single line per parameter \, with the prepended parameter name and the values in the subsequent fields; +#X text 537 44 retrieval; +#X text 31 36 storage; +#X connect 0 0 18 0; +#X connect 0 1 8 0; +#X connect 1 0 9 0; +#X connect 2 0 3 0; +#X connect 2 1 14 1; +#X connect 3 0 5 0; +#X connect 5 0 10 0; +#X connect 5 1 6 0; +#X connect 6 0 14 0; +#X connect 6 1 4 1; +#X connect 7 0 0 0; +#X connect 8 0 7 0; +#X connect 9 0 2 0; +#X connect 9 1 10 1; +#X connect 10 0 11 0; +#X connect 11 0 13 0; +#X connect 11 1 12 0; +#X connect 12 0 13 1; +#X connect 14 0 4 0; +#X connect 15 0 18 0; +#X connect 16 0 15 0; +#X connect 17 0 16 0; +#X connect 18 0 20 0; +#X connect 18 1 19 0; +#X connect 19 0 22 0; +#X connect 20 1 21 0; +#X connect 22 0 21 1; +#X restore 841 64 pd storage; +#X text 399 178 FLOCK PARAMETERS -----------------------------; +#X text 787 179 NEIGHBORS -----------------------------; +#X text 404 347 BOID MOVEMENT -----------------------------; +#X text 786 397 WALL BEHAVIOR -----------------------------; +#X obj 184 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-number \$1-number-set number 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-center \$1-center-set center 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-attract \$1-attract-set attract 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 259 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-prefdist \$1-prefdist-set prefdist 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 259 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-neighbors \$1-neighbors-set neighbors 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-match \$1-match-set match 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 213 nbx 5 18 -1e+37 1e+37 0 0 \$1-avoid \$1-avoid-set avoid 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 259 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-maxspeed \$1-maxspeed-set maxspeed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-speed \$1-speed-set speed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 291 nbx 5 18 -1e+37 1e+37 0 0 \$1-inertia \$1-inertia-set inertia 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 291 nbx 5 18 -1e+37 1e+37 0 0 \$1-accel \$1-accel-set accel 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 252 nbx 5 18 -1e+37 1e+37 0 0 \$1-minspeed \$1-minspeed-set minspeed 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 184 330 nbx 5 18 -1e+37 1e+37 0 0 \$1-repel \$1-repel-set repel 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 109 330 nbx 5 18 -1e+37 1e+37 0 0 \$1-edgedist \$1-edgedist-set edgedist 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X text 393 60 Here are all parameters you can send to the boids external. You can also get the defaults by sending a "dump" message before changing them; +#X obj 259 291 bng 20 250 50 0 \$1-defaults \$1-defaults defaults 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 259 330 bng 20 250 50 0 \$1-output \$1-output output 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 109 134 nbx 5 18 -1e+37 1e+37 0 0 \$1-dimensions \$1-dimensions-set dimensions 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X obj 260 174 nbx 5 18 -1e+37 1e+37 0 0 \$1-bounds \$1-bounds-set bounds 0 -10 0 12 #fcfcfc #000000 #000000 0 256; +#X text 395 215 number: number of boids; +#X text 393 294 center: strength of centering instinct; +#X text 395 252 attractpt: strength of attraction to 'attractpt'; +#X text 404 389 inertia: willingness to change speed and direction; +#X text 403 431 speed: overall speed; +#X text 404 473 min/max speed: speed range; +#X text 406 515 accel: speed of acceleration; +#X text 799 219 neighbors: number of neighbors each boid consults when flocking; +#X text 793 266 match: strength of neighbor speed matching instinct; +#X text 789 308 avoid: strength of neighbor avoidance instinct; +#X text 796 350 prefdist: preferred distance from neighbors; +#X text 794 438 edgedist: distance of vision for avoiding wall edges; +#X text 791 481 repel: strength of wall avoidance instinct; +#X text 789 522 bounds: size of the equally space bounding box as in: -bound +bound \, one pair per dimension, f 45; +#X text 397 132 dimensions: number of dimensions: 1 \, 2 \, 3 \, ...; +#X obj 983 67 text define \$1-parameters; +#X obj 103 387 loadbang; +#X obj 103 412 s \$1-output; +#X connect 2 0 3 0; +#X connect 45 0 46 0; +#X coords 0 -1 1 1 230 270 1 100 100; diff --git a/boids/gemboid.pd b/boids/gemboid.pd new file mode 100644 index 0000000..31a7e6b --- /dev/null +++ b/boids/gemboid.pd @@ -0,0 +1,87 @@ +#N canvas 92 179 719 539 12; +#X obj 61 64 gemhead; +#X obj 61 241 translateXYZ; +#X obj 152 41 inlet; +#N canvas 0 22 474 324 rand_color 0; +#X obj 158 105 random 1000; +#X obj 158 146 * 0.001; +#X obj 224 140 random 1000; +#X obj 224 181 * 0.001; +#X obj 307 141 random 1000; +#X obj 307 182 * 0.001; +#X obj 189 44 t b b b; +#X obj 141 285 outlet; +#X obj 185 19 r \$1-reset; +#X obj 137 8 inlet; +#X obj 139 189 *; +#X obj 143 230 pack f f f; +#X msg 143 255 \$2 \$3 \$1 0; +#X connect 0 0 1 0; +#X connect 1 0 10 1; +#X connect 2 0 3 0; +#X connect 3 0 11 1; +#X connect 4 0 5 0; +#X connect 5 0 11 2; +#X connect 6 0 0 0; +#X connect 6 1 2 0; +#X connect 6 2 4 0; +#X connect 8 0 6 0; +#X connect 9 0 10 0; +#X connect 10 0 11 0; +#X connect 11 0 12 0; +#X connect 12 0 7 0; +#X restore 195 121 pd rand_color; +#X obj 72 433 circle 0.05; +#X text 34 14 helper abstraction for boids examples with Gem; +#X obj 152 202 unpack f f f; +#X obj 284 179 loadbang; +#X obj 284 204 f \$2; +#X obj 203 245 ==; +#X obj 73 371 spigot 1; +#X obj 60 266 t a a; +#X obj 216 332 spigot; +#X obj 254 244 == 1; +#X obj 152 164 list split 3; +#X obj 394 94 list split 3; +#X obj 432 124 unpack f f f; +#X obj 382 391 rotateXYZ; +#X text 426 36 with mode == 2; +#X obj 391 486 sphere3d 0.1 6; +#X obj 453 411 loadbang; +#X obj 61 125 color 1 0.5 0 0; +#X obj 438 463 r \$1-size; +#X msg 453 436 setCartesian 0 0 0 0 2; +#X text 356 120 speed; +#X text 397 145 yaw = azimuth; +#X text 449 369 pitch = elevation; +#X obj 152 103 t a a; +#X obj 228 467 outlet; +#X connect 0 0 21 0; +#X connect 1 0 11 0; +#X connect 2 0 27 0; +#X connect 3 0 21 1; +#X connect 6 0 1 1; +#X connect 6 1 1 2; +#X connect 6 2 1 3; +#X connect 7 0 8 0; +#X connect 8 0 13 0; +#X connect 9 0 10 1; +#X connect 10 0 4 0; +#X connect 11 0 10 0; +#X connect 11 1 12 0; +#X connect 12 0 17 0; +#X connect 13 0 9 0; +#X connect 13 0 12 1; +#X connect 14 0 6 0; +#X connect 14 1 15 0; +#X connect 15 1 16 0; +#X connect 16 0 3 0; +#X connect 16 1 17 1; +#X connect 16 2 17 3; +#X connect 17 0 19 0; +#X connect 20 0 23 0; +#X connect 21 0 1 0; +#X connect 22 0 19 1; +#X connect 23 0 19 0; +#X connect 27 0 14 0; +#X connect 27 1 28 0; diff --git a/boids/point.pd b/boids/point.pd new file mode 100644 index 0000000..bef68c4 --- /dev/null +++ b/boids/point.pd @@ -0,0 +1,83 @@ +#N canvas 825 51 664 704 12; +#X obj 61 13 inlet; +#X obj 137 327 unpack; +#X obj 264 320 cos; +#X obj 296 320 sin; +#X obj 275 215 t f f; +#X obj 127 363 t f f; +#X obj 151 422 *; +#X obj 185 421 *; +#X obj 176 365 t f f; +#X obj 263 423 *; +#X obj 297 422 *; +#X obj 237 363 t f f; +#X obj 288 363 t f f; +#X obj 151 447 -; +#X obj 263 448 +; +#X obj 263 527 +; +#X obj 375 528 +; +#X obj 446 329 unpack; +#X obj 136 156 abs; +#X obj 134 206 * -1; +#X obj 137 117 unpack; +#X obj 436 118 list split 2; +#X obj 113 80 list split 2; +#X obj 263 552 pack; +#X msg 96 537 append \$1 \$2; +#X obj 64 580 list store; +#X obj 58 44 t b a a, f 42; +#X obj 64 605 t a b; +#X obj 64 630 outlet; +#X listbox 152 497 20 0 0 0 - - - 0; +#X listbox 263 473 20 0 0 0 - - - 0; +#X obj 134 231 pack f f f; +#X obj 135 181 t f f f; +#X msg 130 264 \$1 0 \, 0 \$3 \, \$2 0, f 11; +#X obj 195 203 * -3; +#X connect 0 0 26 0; +#X connect 1 0 5 0; +#X connect 1 1 8 0; +#X connect 2 0 11 0; +#X connect 3 0 12 0; +#X connect 4 0 2 0; +#X connect 4 1 3 0; +#X connect 5 0 6 0; +#X connect 5 1 9 0; +#X connect 6 0 13 0; +#X connect 7 0 13 1; +#X connect 8 0 7 0; +#X connect 8 1 10 0; +#X connect 9 0 14 0; +#X connect 10 0 14 1; +#X connect 11 0 6 1; +#X connect 11 1 10 1; +#X connect 12 0 7 1; +#X connect 12 1 9 1; +#X connect 13 0 15 0; +#X connect 13 0 29 0; +#X connect 14 0 16 0; +#X connect 14 0 30 0; +#X connect 15 0 23 0; +#X connect 16 0 23 1; +#X connect 17 0 15 1; +#X connect 17 1 16 1; +#X connect 18 0 32 0; +#X connect 19 0 31 0; +#X connect 20 0 18 0; +#X connect 20 1 4 0; +#X connect 21 0 17 0; +#X connect 22 1 20 0; +#X connect 23 0 24 0; +#X connect 24 0 25 0; +#X connect 25 0 27 0; +#X connect 26 0 25 0; +#X connect 26 1 22 0; +#X connect 26 2 21 0; +#X connect 27 0 28 0; +#X connect 27 1 25 1; +#X connect 31 0 33 0; +#X connect 32 0 19 0; +#X connect 32 1 31 1; +#X connect 32 2 34 0; +#X connect 33 0 1 0; +#X connect 34 0 31 2; diff --git a/boids/struct-boid.pd b/boids/struct-boid.pd new file mode 100644 index 0000000..ae05b5d --- /dev/null +++ b/boids/struct-boid.pd @@ -0,0 +1,50 @@ +#N canvas 576 120 648 513 12; +#X msg 430 259 traverse pd-\$1-data \, bang, f 21; +#X obj 429 315 pointer; +#X obj 430 219 f \$2; +#X obj 48 39 inlet; +#X obj 238 265 point; +#X obj 305 238 s \$0-color; +#X obj 324 277 r \$0-color; +#X obj 242 330 list prepend; +#X msg 324 302 list \$1 \$1 0; +#X obj 59 313 point; +#X obj 237 158 t b b b, f 8; +#X obj 307 207 random 998; +#X obj 52 403 set \$2-template x0 y0 x1 y1 x2 y2, f 16; +#X msg 234 213 0 0 6 0; +#X obj 42 87 list split 2; +#X obj 77 209 list; +#X obj 78 115 list split 2; +#X obj 99 144 unpack f f f; +#X msg 63 257 \$1 \$2 6 \$3; +#X obj 140 168 / 180; +#X obj 134 192 * 3.14156; +#X obj 135 212 * 2; +#X obj 240 120 r \$2-init-boids; +#X obj 240 404 append \$2-template k1 k2 k3 x0 y0 x1 y1 x2 y2, f 25; +#X connect 0 0 1 0; +#X connect 1 0 23 9; +#X connect 2 0 0 0; +#X connect 3 0 14 0; +#X connect 4 0 7 0; +#X connect 6 0 8 0; +#X connect 7 0 23 0; +#X connect 8 0 7 1; +#X connect 9 0 12 0; +#X connect 10 0 13 0; +#X connect 10 1 11 0; +#X connect 10 2 2 0; +#X connect 11 0 5 0; +#X connect 13 0 4 0; +#X connect 14 0 15 0; +#X connect 14 1 16 0; +#X connect 15 0 18 0; +#X connect 16 1 17 0; +#X connect 17 1 19 0; +#X connect 18 0 9 0; +#X connect 19 0 20 0; +#X connect 20 0 21 0; +#X connect 21 0 15 1; +#X connect 22 0 10 0; +#X connect 23 0 12 6; diff --git a/boids2d-help.pd b/boids2d-help.pd deleted file mode 100644 index 331a09d..0000000 --- a/boids2d-help.pd +++ /dev/null @@ -1,294 +0,0 @@ -#N canvas 369 326 1021 718 10; -#X declare -lib Gem; -#X msg 121 601 dump; -#X msg 486 113 neighbors \$1; -#X floatatom 446 96 5 0 4 0 - \$0-neighbors - 0; -#X floatatom 446 131 5 0 0 0 - \$0-maxspeed - 0; -#X msg 486 148 maxspeed \$1; -#X floatatom 446 166 5 0 0 0 - \$0-minspeed - 0; -#X msg 486 183 minspeed \$1; -#X floatatom 446 201 5 0 0 0 - \$0-center - 0; -#X msg 486 218 center \$1; -#X floatatom 446 236 5 0 0 0 - \$0-attract - 0; -#X msg 486 253 attract \$1; -#X floatatom 446 271 5 0 0 0 - \$0-match - 0; -#X msg 486 288 match \$1; -#X floatatom 446 306 5 0 0 0 - \$0-avoid - 0; -#X msg 486 323 avoid \$1; -#X floatatom 446 341 5 0 0 0 - \$0-repel - 0; -#X msg 486 358 repel \$1; -#X floatatom 446 376 5 0 0 0 - \$0-edgedist - 0; -#X msg 486 393 edgedist \$1; -#X floatatom 446 411 5 0 0 0 - \$0-speed - 0; -#X msg 486 428 speed \$1; -#X floatatom 446 446 5 0 0 0 - \$0-inertia - 0; -#X msg 486 463 inertia \$1; -#X floatatom 446 481 5 0 0 0 - \$0-accel - 0; -#X msg 486 498 accel \$1; -#X floatatom 446 516 5 0 0 0 - \$0-prefdist - 0; -#X msg 486 533 prefdist \$1; -#X msg 121 620 reset; -#X text 577 148 maximum speed of speed range; -#X text 579 182 minimum speed of speed range; -#X text 576 217 strength of centering instinct; -#X text 578 428 overall speed; -#X text 579 499 speed of acceleration; -#X text 579 530 preferred distance from neighbors; -#X floatatom 487 556 5 0 0 0 - \$0-flyrect0 - 0; -#X floatatom 526 556 5 0 0 0 - \$0-flyrect1 - 0; -#X floatatom 565 556 5 0 0 0 - \$0-flyrect2 - 0; -#X floatatom 604 556 5 0 0 0 - \$0-flyrect4 - 0; -#X floatatom 486 625 5 0 0 0 - - - 0; -#X floatatom 526 625 5 0 0 0 - - - 0; -#X floatatom 446 61 5 0 0 0 - \$0-number - 0; -#X msg 486 78 number \$1; -#X text 577 76 number of boids; -#X floatatom 121 567 5 0 0 0 - - - 0; -#X msg 121 582 mode \$1; -#X text 185 582 output mode; -#X text 185 601 parameter dump; -#X text 184 621 reset boids randomly inside flyrect; -#X text 577 111 number of neighbors each boid consults when flocking; -#X text 576 288 strength of neighbor speed matching instinct; -#X text 576 323 strength of neighbor avoidance instinct; -#X text 576 355 strength of wall avoidance instinct; -#X text 578 391 distance of vision for avoiding wall edges; -#X text 579 462 willingness to change speed and direction; -#X text 575 251 strength of attraction to 'attractpt'; -#X text 29 84 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); -#X text 29 126 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; -#X text 29 159 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; -#X text 29 208 Boids takes an integer argument which is the number of boids. Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of thew coordiantes for each boid \, the number and type depending on the mode.; -#X text 30 282 The flight parameters can be changed with messages. Use the 'dump' message to output a list of the current parameter settings.; -#X text 30 328 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; -#X text 32 64 arguments: number of boids \, output mode; -#X obj 148 460 print dump; -#X obj 17 9 cnv 15 800 48 empty empty boids2d 20 12 2 24 #dce0c8 #404040 0; -#X obj 69 410 bng 15 250 50 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000; -#N canvas 845 12 635 438 gem_example 0; -#X msg 33 31 destroy; -#N canvas 494 140 629 324 gemwin 0; -#X obj 209 190 gemwin; -#X obj 67 194 outlet; -#X obj 67 10 inlet; -#X obj 67 41 route create; -#X msg 67 70 set destroy; -#X msg 157 70 set create; -#X msg 350 115 destroy \, reset; -#X obj 157 18 loadbang; -#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.5; -#X msg 238 71 color 1 1 1; -#X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 3 0 8 0; -#X connect 3 1 5 0; -#X connect 3 1 6 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X connect 6 0 0 0; -#X connect 7 0 5 0; -#X connect 8 0 0 0; -#X connect 9 0 0 0; -#X restore 33 51 pd gemwin; -#X obj 33 91 tgl 15 0 empty empty start_flocking_animation 20 6 1 10 #fcfcfc #000000 #000000 0 1; -#X obj 33 112 metro 33; -#X floatatom 33 244 5 0 0 0 - - - 0; -#X floatatom 78 244 5 0 0 0 - - - 0; -#X text 96 30 create/destroy OpenGl context; -#X obj 33 181 spigot; -#X obj 69 160 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 0 1; -#N canvas 0 22 418 379 center 0; -#X obj 101 37 gemhead; -#X obj 99 201 translateXYZ; -#X obj 124 166 unpack 0 0 0; -#X obj 147 94 inlet; -#X msg 240 193 draw line; -#X obj 252 106 loadbang; -#X obj 100 131 alpha; -#X obj 101 68 color 1 0.5 0 0.5; -#X obj 99 228 circle 0.1; -#X connect 0 0 7 0; -#X connect 1 0 8 0; -#X connect 2 0 1 1; -#X connect 2 1 1 2; -#X connect 2 2 1 3; -#X connect 3 0 2 0; -#X connect 4 0 8 0; -#X connect 5 0 4 0; -#X connect 6 0 1 0; -#X connect 7 0 6 0; -#X restore 33 342 pd center; -#X msg 85 295 attractpt \$1 \$2; -#X obj 33 267 pack 0 0; -#X obj 205 163 boids2d 10; -#N canvas 0 22 466 396 orbit 0; -#X floatatom 103 160 5 0 0 0 - - - 0; -#X obj 103 187 expr $f1 * (3.141593/180.); -#X obj 103 45 inlet; -#X obj 166 314 outlet; -#X obj 103 314 outlet; -#N canvas 0 0 450 300 pol2cart 0; -#X obj 79 42 inlet r; -#X obj 159 42 inlet phi; -#X obj 79 231 outlet x; -#X obj 146 231 outlet y; -#X obj 146 120 t f f; -#X obj 146 144 cos; -#X obj 176 144 sin; -#X obj 79 171 t f f, f 10; -#X obj 79 197 * 1; -#X obj 146 196 * 0; -#X obj 79 93 unpack 0 0; -#X obj 79 65 pack \$1 \$2; -#X connect 0 0 11 0; -#X connect 1 0 11 1; -#X connect 4 0 5 0; -#X connect 4 1 6 0; -#X connect 5 0 8 1; -#X connect 6 0 9 1; -#X connect 7 0 8 0; -#X connect 7 1 9 0; -#X connect 8 0 2 0; -#X connect 9 0 3 0; -#X connect 10 0 7 0; -#X connect 10 1 4 0; -#X connect 11 0 10 0; -#X restore 103 254 pd pol2cart; -#X msg 103 210 1.5 \$1; -#X obj 103 277 swap, f 11; -#X obj 103 68 i; -#X obj 103 91 + 1; -#X obj 103 114 % 360; -#X obj 103 137 t f f; -#X connect 0 0 1 0; -#X connect 1 0 6 0; -#X connect 2 0 8 0; -#X connect 5 0 7 0; -#X connect 5 1 7 1; -#X connect 6 0 5 0; -#X connect 7 0 4 0; -#X connect 7 1 3 0; -#X connect 8 0 9 0; -#X connect 9 0 10 0; -#X connect 10 0 11 0; -#X connect 11 0 0 0; -#X connect 11 1 8 1; -#X restore 33 205 pd orbit; -#X obj 322 61 t f b; -#X obj 322 13 loadbang; -#X msg 322 36 1; -#X obj 85 318 s \$0-boidParam; -#X obj 205 190 clone -x examples/gemboid 10 \$0; -#X obj 205 135 r \$0-boidParam; -#X obj 33 133 t b b; -#X obj 349 83 s \$0-init; -#X obj 33 290 t a a; -#X connect 0 0 1 0; -#X connect 1 0 0 0; -#X connect 2 0 3 0; -#X connect 3 0 20 0; -#X connect 4 0 11 0; -#X connect 5 0 11 1; -#X connect 7 0 13 0; -#X connect 8 0 7 1; -#X connect 10 0 17 0; -#X connect 11 0 22 0; -#X connect 12 0 18 0; -#X connect 13 0 4 0; -#X connect 13 1 5 0; -#X connect 14 0 8 0; -#X connect 14 1 21 0; -#X connect 15 0 16 0; -#X connect 16 0 14 0; -#X connect 19 0 12 0; -#X connect 20 0 7 0; -#X connect 20 1 12 0; -#X connect 22 0 9 0; -#X connect 22 1 10 0; -#X restore 277 437 pd gem_example; -#X obj 486 642 pack 0 0 0; -#X floatatom 565 625 5 0 0 0 - - - 0; -#X text 30 105 float/2d/3d adaptation 08/2005 by a. sier / jasch; -#N canvas 1146 116 222 383 init 0; -#X obj 34 21 loadbang; -#X obj 17 79 b; -#X obj 17 112 list prepend \$0; -#X msg 17 145 \; \$1-neighbors 4 \; \$1-maxspeed 1.5 \; \$1-minspeed 1.2 \; \$1-center 1.2 \; \$1-attract 1.25 \; \$1-match 0.3 \; \$1-avoid 3.5 \; \$1-repel 3.5 \; \$1-edgedist 3 \; \$1-speed 3 \; \$1-inertia 4.5 \; \$1-accel 2.5 \; \$1-prefdist 1.5, f 17; -#X obj 94 21 r \$0-reset; -#X obj 111 52 inlet; -#X connect 0 0 1 0; -#X connect 1 0 2 0; -#X connect 2 0 3 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X restore 277 407 pd init; -#X obj 69 438 boids2d 16 0; -#X obj 69 488 print boids2d; -#X msg 486 602 flyrect \$1 \$2 \$3 \$4; -#X msg 486 662 attractpt \$1 \$2; -#X text 609 614 point to which boids are attracted (x/y); -#X text 612 575 bounding box (walls) in which to fly (l/t/r/b); -#N canvas 88 105 494 344 META 0; -#X text 12 165 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; -#X text 12 145 AUTHOR Eric L. Singer; -#X text 12 5 KEYWORDS control; -#X text 12 45 DESCRIPTION bird flight and animal flock simulator; -#X text 12 65 INLET_0 bang dump mode reset number neighbors maxspeed minspeed center attract match avoid repel edgedist speed inertia accel prefdist flyrect attractpt; -#X text 12 105 OUTLET_0 list; -#X text 12 125 OUTLET_1 list; -#X text 12 25 LICENSE GPL v2; -#X restore 940 676 pd META; -#X obj 822 23 declare -lib Gem; -#X obj 121 641 s \$0-boidParam; -#X obj 95 411 r \$0-boidParam; -#X obj 486 686 s \$0-boidParam; -#X obj 486 584 pack 0 0 0 0, f 20; -#X obj 277 387 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; -#X connect 0 0 78 0; -#X connect 1 0 80 0; -#X connect 2 0 1 0; -#X connect 3 0 4 0; -#X connect 4 0 80 0; -#X connect 5 0 6 0; -#X connect 6 0 80 0; -#X connect 7 0 8 0; -#X connect 8 0 80 0; -#X connect 9 0 10 0; -#X connect 10 0 80 0; -#X connect 11 0 12 0; -#X connect 12 0 80 0; -#X connect 13 0 14 0; -#X connect 14 0 80 0; -#X connect 15 0 16 0; -#X connect 16 0 80 0; -#X connect 17 0 18 0; -#X connect 18 0 80 0; -#X connect 19 0 20 0; -#X connect 20 0 80 0; -#X connect 21 0 22 0; -#X connect 22 0 80 0; -#X connect 23 0 24 0; -#X connect 24 0 80 0; -#X connect 25 0 26 0; -#X connect 26 0 80 0; -#X connect 27 0 78 0; -#X connect 34 0 81 0; -#X connect 35 0 81 1; -#X connect 36 0 81 2; -#X connect 37 0 81 3; -#X connect 38 0 66 0; -#X connect 39 0 66 1; -#X connect 40 0 41 0; -#X connect 41 0 80 0; -#X connect 43 0 44 0; -#X connect 44 0 78 0; -#X connect 64 0 70 0; -#X connect 66 0 73 0; -#X connect 67 0 66 2; -#X connect 70 0 71 0; -#X connect 70 1 62 0; -#X connect 72 0 80 0; -#X connect 73 0 80 0; -#X connect 79 0 70 0; -#X connect 81 0 72 0; -#X connect 82 0 69 0; diff --git a/boids2d.c b/boids2d.c deleted file mode 100644 index a05e522..0000000 --- a/boids2d.c +++ /dev/null @@ -1,962 +0,0 @@ -/* - - boids2d 08/2005 a.sier / jasch adapted from boids by eric singer 1995-2003 eric l. singer - - 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 -*/ - -#include "m_pd.h" -#include -#include - -// constants -#define kAssistInlet 1 -#define kAssistOutlet 2 -#define kMaxLong 0xFFFFFFFF -#define kMaxNeighbors 4 - -// util -#define MAX(a,b) ((a)>(b)?(a):(b)) -#define CLIP(x,a,b) (x)=(x)<(a)?(a):(x)>(b)?(b):(x) - -// initial flight parameters -const short kNumBoids = 12; // number of boids -const short kNumNeighbors = 2; // must be <= kMaxNeighbors -const double kMinSpeed = 0.15; // boids' minimum speed -const double kMaxSpeed = 0.25; // boids' maximum speed -const double kCenterWeight = 0.25; // flock centering -const double kAttractWeight = 0.300;// attraction point seeking -const double kMatchWeight = 0.100;// neighbors velocity matching -const double kAvoidWeight = 0.10; // neighbors avoidance -const double kWallsWeight = 0.500;// wall avoidance [210] -const double kEdgeDist = 0.5; // vision distance to avoid wall edges [5] -const double kSpeedupFactor = 0.100;// alter animation speed -const double kInertiaFactor = 0.20; // willingness to change speed & direction -const double kAccelFactor = 0.100;// neighbor avoidance accelerate or decelerate rate -const double kPrefDist = 0.25; // preferred distance from neighbors -const double kFlyRectTop = 1.0; // fly rect boundaries -const double kFlyRectLeft = -1.0; -const double kFlyRectBottom = -1.0; -const double kFlyRectRight = 1.0; -// const double kFlyRectFront = 1.0; -// const double kFlyRectBack = -1.0; - - -// typedefs -typedef struct Velocity { - double x; - double y; -// double z; -} Velocity; - -typedef struct Point2d { - double x; - double y; -// double z; -} Point2d; - -typedef struct Box3D { - double left, right; - double top, bottom; -// double front, back; -} Box3D; - -typedef struct _Boid { - Point2d oldPos; - Point2d newPos; - Velocity oldDir; - Velocity newDir; - double speed; - short neighbor[kMaxNeighbors]; - double neighborDistSqr[kMaxNeighbors]; -} t_one_boid, *BoidPtr; - -typedef struct _FlockObject { - t_object ob; - void *out1, *out2; - short mode; - long numBoids; - long numNeighbors; - Box3D flyRect; - double minSpeed; - double maxSpeed; - double centerWeight; - double attractWeight; - double matchWeight; - double avoidWeight; - double wallsWeight; - double edgeDist; - double speedupFactor; - double inertiaFactor; - double accelFactor; - double prefDist; - double prefDistSqr; - Point2d centerPt; - Point2d attractPt; - BoidPtr boid; - double d2r, r2d; -} t_boids, *FlockPtr; - -// variables -// void *flock; -t_symbol *ps_nothing; - -// prototypes -void *boids2d_class; -void *Flock_new(t_symbol *s, long argc, t_atom *argv); -void Flock_free(t_boids *x); -void Flock_bang(t_boids *x); -void Flock_dump(t_boids *x); -void Flock_mode(t_boids *x, t_float arg); -void Flock_numNeighbors(t_boids *x, t_float arg); -void Flock_numBoids(t_boids *x, t_float arg); -void Flock_minSpeed(t_boids *x, t_float arg); -void Flock_maxSpeed(t_boids *x, t_float arg); -void Flock_centerWeight(t_boids *x, t_float arg); -void Flock_attractWeight(t_boids *x, t_float arg); -void Flock_matchWeight(t_boids *x, t_float arg); -void Flock_avoidWeight(t_boids *x, t_float arg); -void Flock_wallsWeight(t_boids *x, t_float arg); -void Flock_edgeDist(t_boids *x, t_float arg); -void Flock_speedupFactor(t_boids *x, t_float arg); -void Flock_inertiaFactor(t_boids *x, t_float arg); -void Flock_accelFactor(t_boids *x, t_float arg); -void Flock_prefDist(t_boids *x, t_float arg); -void Flock_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv); -void Flock_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv); -void Flock_reset(t_boids *x); -void Flock_resetBoids(t_boids *x); -void InitFlock(t_boids *x); -void FlightStep(t_boids *x); -Point2d FindFlockCenter(t_boids *x); -float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborVel, Velocity *avoidNeighborVel); -Velocity SeekPoint(t_boids *x, short theBoid, Point2d seekPt); -Velocity AvoidWalls(t_boids *x, short theBoid); -int InFront(BoidPtr theBoid, BoidPtr neighbor); -void NormalizeVelocity(Velocity *direction); -double RandomInt(double minRange, double maxRange); -double DistSqrToPt(Point2d firstPoint, Point2d secondPoint); - -void boids2d_setup(void) -{ - boids2d_class = class_new(gensym("boids2d"), (t_newmethod)Flock_new, - (t_method)Flock_free, sizeof(t_boids), 0, A_GIMME, 0); - /* setup((t_messlist **) &flock, (method)Flock_new, (method)Flock_free, (short) sizeof(FlockObject), 0L, A_LONG, A_DEFLONG, 0); */ - class_addfloat(boids2d_class, (t_method) Flock_numBoids); - class_addbang(boids2d_class, (t_method) Flock_bang); - class_addmethod(boids2d_class, (t_method) Flock_numNeighbors, gensym("neighbors"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_numBoids, gensym("number"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_mode, gensym("mode"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_minSpeed, gensym("minspeed"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_maxSpeed, gensym("maxspeed"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_centerWeight, gensym("center"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_attractWeight, gensym("attract"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_matchWeight, gensym("match"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_avoidWeight, gensym("avoid"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_wallsWeight, gensym("repel"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_edgeDist, gensym("edgedist"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_speedupFactor, gensym("speed"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_inertiaFactor, gensym("inertia"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_accelFactor, gensym("accel"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_prefDist, gensym("prefdist"), A_FLOAT, 0); - class_addmethod(boids2d_class, (t_method) Flock_flyRect, gensym("flyrect"), A_GIMME, 0); - class_addmethod(boids2d_class, (t_method) Flock_attractPt, gensym("attractpt"), A_GIMME, 0); - class_addmethod(boids2d_class, (t_method) Flock_resetBoids, gensym("reset"), 0); - class_addmethod(boids2d_class, (t_method) Flock_reset, gensym("init"), 0); - class_addmethod(boids2d_class, (t_method) Flock_dump, gensym("dump"), 0); - - logpost(NULL, 4, "boids2d 2005-2006 a.sier / jasch 1995-2003 eric l. singer "__DATE__" "__TIME__); - ps_nothing = gensym(""); -} - - -void *Flock_new(t_symbol *s, long argc, t_atom *argv) -{ - t_boids *x = (t_boids *)pd_new(boids2d_class); - x->out1 = outlet_new(&x->ob, NULL); - x->out2 = outlet_new(&x->ob, NULL); - - x->numBoids = 16; - if((argc >= 1) && (argv[0].a_type == A_FLOAT)){ - x->numBoids = argv[0].a_w.w_float; - } - x->boid = (t_one_boid *)malloc(sizeof(t_one_boid) * x->numBoids); - - InitFlock(x); - - x->mode = 0; - if((argc >= 2) && (argv[1].a_type == A_FLOAT)){ - x->mode = (short)(CLIP(argv[1].a_w.w_float, 0, 2)); - } - - x->d2r = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068/180.0; - x->r2d = 180.0/3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068; - - return(x); -} - - -void Flock_free(t_boids *x) -{ - free(x->boid); -} - -void Flock_bang(t_boids *x) -{ - short i; - t_atom outlist[10]; - t_atom *out; - - double tempNew_x, tempNew_y; - double tempOld_x, tempOld_y; - double delta_x, delta_y; - double azi, speed; - // double tempspeed; - - out = outlist; - - FlightStep(x); - - - switch(x->mode) { // newpos - case 0: - for (i = 0; i < x->numBoids; i++){ - SETFLOAT(out+0, i); - SETFLOAT(out+1, x->boid[i].newPos.x); - SETFLOAT(out+2, x->boid[i].newPos.y); - // SETFLOAT(out+3, x->boid[i].newPos.z); - outlet_list(x->out1, 0L, 3, out); - } - break; - case 1: //newpos + oldpos - for (i = 0; i < x->numBoids; i++){ - SETFLOAT(out+0, i); - SETFLOAT(out+1, x->boid[i].newPos.x); - SETFLOAT(out+2, x->boid[i].newPos.y); - // SETFLOAT(out+3, x->boid[i].newPos.z); - SETFLOAT(out+3, x->boid[i].oldPos.x); - SETFLOAT(out+4, x->boid[i].oldPos.y); - // SETFLOAT(out+6, x->boid[i].oldPos.z); - outlet_list(x->out1, 0L, 5, out); - } - break; - case 2: - for (i = 0; i < x->numBoids; i++){ - tempNew_x = x->boid[i].newPos.x; - tempNew_y = x->boid[i].newPos.y; - // tempNew_z = x->boid[i].newPos.z; - tempOld_x = x->boid[i].oldPos.x; - tempOld_y = x->boid[i].oldPos.y; - // tempOld_z = x->boid[i].oldPos.z; - delta_x = tempNew_x - tempOld_x; - delta_y = tempNew_y - tempOld_y; - // delta_z = tempNew_z - tempOld_z; - azi = atan2(delta_y, delta_x) * x->r2d; - // ele = atan2(delta_y, delta_x) * x->r2d; - speed = sqrt(delta_x * delta_x + delta_y * delta_y);// + delta_z * delta_z); - SETFLOAT(out+0, i); - SETFLOAT(out+1, tempNew_x); - SETFLOAT(out+2, tempNew_y); - // SETFLOAT(out+3, tempNew_z); - SETFLOAT(out+3, tempOld_x); - SETFLOAT(out+4, tempOld_y); - // SETFLOAT(out+6, tempOld_z); - SETFLOAT(out+5, speed); - SETFLOAT(out+6, azi); - // SETFLOAT(out+9, ele); - outlet_list(x->out1, 0L, 7, out); - } - break; - } -} - -void Flock_dump(t_boids *x) -{ - t_atom outList[6]; - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->numNeighbors; - outlet_anything(x->out2, gensym("neighbors"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->minSpeed; - outlet_anything(x->out2, gensym("minspeed"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->maxSpeed; - outlet_anything(x->out2, gensym("maxspeed"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->centerWeight; - outlet_anything(x->out2, gensym("center"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->attractWeight; - outlet_anything(x->out2, gensym("attract"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->matchWeight; - outlet_anything(x->out2, gensym("match"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->avoidWeight; - outlet_anything(x->out2, gensym("avoid"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->wallsWeight; - outlet_anything(x->out2, gensym("repel"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->edgeDist; - outlet_anything(x->out2, gensym("edgedist"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->speedupFactor; - outlet_anything(x->out2, gensym("speed"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->inertiaFactor; - outlet_anything(x->out2, gensym("inertia"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->accelFactor; - outlet_anything(x->out2, gensym("accel"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->prefDist; - outlet_anything(x->out2, gensym("prefdist"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->flyRect.left; - outList[1].a_type = A_FLOAT; - outList[1].a_w.w_float = x->flyRect.top; - outList[2].a_type = A_FLOAT; - outList[2].a_w.w_float = x->flyRect.right; - outList[3].a_type = A_FLOAT; - outList[3].a_w.w_float = x->flyRect.bottom; - /*outList[4].a_type = A_FLOAT; - outList[4].a_w.w_float = x->flyRect.front; - outList[5].a_type = A_FLOAT; - outList[5].a_w.w_float = x->flyRect.back;*/ - outlet_anything(x->out2, gensym("flyrect"), 4, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->attractPt.x; - outList[1].a_type = A_FLOAT; - outList[1].a_w.w_float = x->attractPt.y; - /*outList[2].a_type = A_FLOAT; - outList[2].a_w.w_float = x->attractPt.z;*/ - outlet_anything(x->out2, gensym("attractpt"), 2, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->mode; - outlet_anything(x->out2, gensym("mode"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->numBoids; - outlet_anything(x->out2, gensym("number"), 1, outList); -} - - -void Flock_mode(t_boids *x, t_float arg) -{ - long m = (long)arg; - x->mode = CLIP(m, 0, 2); -} - -void Flock_numNeighbors(t_boids *x, t_float arg) -{ - x->numNeighbors = (long)arg; -} - -void Flock_numBoids(t_boids *x, t_float arg) -{ - x->boid = (t_one_boid *)realloc(x->boid, sizeof(t_one_boid) * (long)arg); - x->numBoids = (long)arg; - Flock_resetBoids(x); -} - -void Flock_minSpeed(t_boids *x, t_float arg) -{ - x->minSpeed = MAX(arg, 0.000001); -} - -void Flock_maxSpeed(t_boids *x, t_float arg) -{ - x->maxSpeed = (double)arg; -} - -void Flock_centerWeight(t_boids *x, t_float arg) -{ - x->centerWeight = (double)arg; -} - -void Flock_attractWeight(t_boids *x, t_float arg) -{ - x->attractWeight = (double)arg; -} - -void Flock_matchWeight(t_boids *x, t_float arg) -{ - x->matchWeight = (double)arg; -} - -void Flock_avoidWeight(t_boids *x, t_float arg) -{ - x->avoidWeight = (double)arg; -} - -void Flock_wallsWeight(t_boids *x, t_float arg) -{ - x->wallsWeight = (double)arg; -} - -void Flock_edgeDist(t_boids *x, t_float arg) -{ - x->edgeDist = (double)arg; -} - -void Flock_speedupFactor(t_boids *x, t_float arg) -{ - x->speedupFactor = (double)arg; -} - -void Flock_inertiaFactor(t_boids *x, t_float arg) -{ - if(arg == 0){ - x->inertiaFactor = 0.000001; - }else{ - x->inertiaFactor = (double)arg; - } -} - -void Flock_accelFactor(t_boids *x, t_float arg) -{ - x->accelFactor = (double)arg; -} - -void Flock_prefDist(t_boids *x, t_float arg) -{ - x->prefDist = (double)arg; -} - -void Flock_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv) -{ - double temp[4]; - short i; - if(argc == 4){ - for(i=0;i<4;i++) { - if(argv[i].a_type == A_FLOAT) { - temp[i] = (double)argv[i].a_w.w_float; - } - } - x->flyRect.left = temp[0]; - x->flyRect.top = temp[1]; - x->flyRect.right = temp[2]; - x->flyRect.bottom = temp[3]; - // x->flyRect.front = temp[4]; - // x->flyRect.back = temp[5]; - }else{ - pd_error(x, "boids2d: flyrect needs four values"); - } -} - -void Flock_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv) -{ - double temp[2]; - short i; - if(argc == 2){ - for(i=0;i<2;i++) { - if(argv[i].a_type == A_FLOAT) { - temp[i] = (double)argv[i].a_w.w_float; - } - } - x->attractPt.x = temp[0]; - x->attractPt.y = temp[1]; - // x->attractPt.z = temp[2]; - }else{ - pd_error(x, "boids2d: attractPt needs two values"); - } -} - -void Flock_reset(t_boids *x) -{ - InitFlock(x); -} - -void Flock_resetBoids(t_boids *x) -{ - long i, j; - double rndAngle; - - for (i = 0; i < x->numBoids; i++) { // init everything to 0.0 - x->boid[i].oldPos.x = 0.0; - x->boid[i].oldPos.y = 0.0; - // x->boid[i].oldPos.z = 0.0; - - x->boid[i].newPos.x = 0.0; - x->boid[i].newPos.y = 0.0; - // x->boid[i].newPos.z = 0.0; - - x->boid[i].oldDir.x = 0.0; - x->boid[i].oldDir.y = 0.0; - // x->boid[i].oldDir.z = 0.0; - - x->boid[i].newDir.x = 0.0; - x->boid[i].newDir.y = 0.0; - // x->boid[i].newDir.z = 0.0; - - x->boid[i].speed = 0.0; - - for(j=0; jboid[i].neighbor[j] = 0; - x->boid[i].neighborDistSqr[j] = 0.0; - } - } - for (i = 0; i < x->numBoids; i++) { // set the initial locations and velocities of the boids - x->boid[i].newPos.x = x->boid[i].oldPos.x = RandomInt(x->flyRect.right,x->flyRect.left); // set random location within flyRect - x->boid[i].newPos.y = x->boid[i].oldPos.y = RandomInt(x->flyRect.bottom, x->flyRect.top); - // x->boid[i].newPos.z = x->boid[i].oldPos.z = RandomInt(x->flyRect.back, x->flyRect.front); - rndAngle = RandomInt(0, 360) * x->d2r; // set velocity from random angle - x->boid[i].newDir.x = sin(rndAngle); - x->boid[i].newDir.y = cos(rndAngle); - // x->boid[i].newDir.z = (cos(rndAngle) + sin(rndAngle)) * 0.5; - x->boid[i].speed = (kMaxSpeed + kMinSpeed) * 0.5; - } -} - -void InitFlock(t_boids *x) -{ - x->numNeighbors = kNumNeighbors; - x->minSpeed = kMinSpeed; - x->maxSpeed = kMaxSpeed; - x->centerWeight = kCenterWeight; - x->attractWeight = kAttractWeight; - x->matchWeight = kMatchWeight; - x->avoidWeight = kAvoidWeight; - x->wallsWeight = kWallsWeight; - x->edgeDist = kEdgeDist; - x->speedupFactor = kSpeedupFactor; - x->inertiaFactor = kInertiaFactor; - x->accelFactor = kAccelFactor; - x->prefDist = kPrefDist; - x->prefDistSqr = kPrefDist * kPrefDist; - x->flyRect.top = kFlyRectTop; - x->flyRect.left = kFlyRectLeft; - x->flyRect.bottom = kFlyRectBottom; - x->flyRect.right = kFlyRectRight; - // x->flyRect.front = kFlyRectFront; - // x->flyRect.back = kFlyRectBack; - x->attractPt.x = (kFlyRectLeft + kFlyRectRight) * 0.5; - x->attractPt.y = (kFlyRectTop + kFlyRectBottom) * 0.5; - // x->attractPt.z = (kFlyRectFront + kFlyRectBack) * 0.5; - Flock_resetBoids(x); -} - -void FlightStep(t_boids *x) -{ - Velocity goCenterVel; - Velocity goAttractVel; - Velocity matchNeighborVel; - Velocity avoidWallsVel; - Velocity avoidNeighborVel; - float avoidNeighborSpeed; - const Velocity zeroVel = {0.0, 0.0};//, 0.0}; - short i; - - x->centerPt = FindFlockCenter(x); - for (i = 0; i < x->numBoids; i++) { // save position and velocity - x->boid[i].oldPos.x = x->boid[i].newPos.x; - x->boid[i].oldPos.y = x->boid[i].newPos.y; - // x->boid[i].oldPos.z = x->boid[i].newPos.z; - - x->boid[i].oldDir.x = x->boid[i].newDir.x; - x->boid[i].oldDir.y = x->boid[i].newDir.y; - // x->boid[i].oldDir.z = x->boid[i].newDir.z; - } - for (i = 0; i < x->numBoids; i++) { - if (x->numNeighbors > 0) { // get all velocity components - avoidNeighborSpeed = MatchAndAvoidNeighbors(x, i,&matchNeighborVel, &avoidNeighborVel); - } else { - matchNeighborVel = zeroVel; - avoidNeighborVel = zeroVel; - avoidNeighborSpeed = 0; - } - goCenterVel = SeekPoint(x, i, x->centerPt); - goAttractVel = SeekPoint(x, i, x->attractPt); - avoidWallsVel = AvoidWalls(x, i); - - // compute resultant velocity using weights and inertia - x->boid[i].newDir.x = x->inertiaFactor * (x->boid[i].oldDir.x) + - (x->centerWeight * goCenterVel.x + - x->attractWeight * goAttractVel.x + - x->matchWeight * matchNeighborVel.x + - x->avoidWeight * avoidNeighborVel.x + - x->wallsWeight * avoidWallsVel.x) / x->inertiaFactor; - x->boid[i].newDir.y = x->inertiaFactor * (x->boid[i].oldDir.y) + - (x->centerWeight * goCenterVel.y + - x->attractWeight * goAttractVel.y + - x->matchWeight * matchNeighborVel.y + - x->avoidWeight * avoidNeighborVel.y + - x->wallsWeight * avoidWallsVel.y) / x->inertiaFactor; - /*x->boid[i].newDir.z = x->inertiaFactor * (x->boid[i].oldDir.z) + - (x->centerWeight * goCenterVel.z + - x->attractWeight * goAttractVel.z + - x->matchWeight * matchNeighborVel.z + - x->avoidWeight * avoidNeighborVel.z + - x->wallsWeight * avoidWallsVel.z) / x->inertiaFactor;*/ - NormalizeVelocity(&(x->boid[i].newDir)); // normalize velocity so its length is unity - - // set to avoidNeighborSpeed bounded by minSpeed and maxSpeed - if ((avoidNeighborSpeed >= x->minSpeed) && - (avoidNeighborSpeed <= x->maxSpeed)) - x->boid[i].speed = avoidNeighborSpeed; - else if (avoidNeighborSpeed > x->maxSpeed) - x->boid[i].speed = x->maxSpeed; - else - x->boid[i].speed = x->minSpeed; - - // calculate new position, applying speedupFactor - x->boid[i].newPos.x += x->boid[i].newDir.x * x->boid[i].speed * (x->speedupFactor / 100.0); - x->boid[i].newPos.y += x->boid[i].newDir.y * x->boid[i].speed * (x->speedupFactor / 100.0); - // x->boid[i].newPos.z += x->boid[i].newDir.z * x->boid[i].speed * (x->speedupFactor / 100.0); - - } -} - -Point2d FindFlockCenter(t_boids *x) -{ - double totalH = 0, totalV = 0, totalD = 0; - Point2d centerPoint; - short i; - - for (i = 0 ; i < x->numBoids; i++) - { - totalH += x->boid[i].oldPos.x; - totalV += x->boid[i].oldPos.y; - // totalD += x->boid[i].oldPos.z; - } - centerPoint.x = (double)(totalH / x->numBoids); - centerPoint.y = (double)(totalV / x->numBoids); - // centerPoint.z = (double) (totalD / x->numBoids); - - return(centerPoint); -} - -float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborVel, Velocity *avoidNeighborVel) -{ - short i, j, neighbor; - double distSqr; - double dist, distH, distV,distD; - double tempSpeed; - short numClose = 0; - Velocity totalVel = {0.0,0.0};//,0.0}; - - /**********************/ - /* Find the neighbors */ - /**********************/ - - /* special case of one neighbor */ - if (x->numNeighbors == 1) { - x->boid[theBoid].neighborDistSqr[0] = kMaxLong; - - for (i = 0; i < x->numBoids; i++) { - if (i != theBoid) { - distSqr = DistSqrToPt(x->boid[theBoid].oldPos, x->boid[i].oldPos); - - /* if this one is closer than the closest so far, then remember it */ - if (x->boid[theBoid].neighborDistSqr[0] > distSqr) { - x->boid[theBoid].neighborDistSqr[0] = distSqr; - x->boid[theBoid].neighbor[0] = i; - } - } - } - } - /* more than one neighbor */ - else { - for (j = 0; j < x->numNeighbors; j++) - x->boid[theBoid].neighborDistSqr[j] = kMaxLong; - - for (i = 0 ; i < x->numBoids; i++) { - /* if this one is not me... */ - if (i != theBoid) { - distSqr = DistSqrToPt(x->boid[theBoid].oldPos, x->boid[i].oldPos); - - /* if distSqr is less than the distance at the bottom of the array, sort into array */ - if (distSqr < x->boid[theBoid].neighborDistSqr[x->numNeighbors-1]) { - j = x->numNeighbors - 1; - - /* sort distSqr in to keep array in size order, smallest first */ - while ((distSqr < x->boid[theBoid].neighborDistSqr[j-1]) && (j > 0)) { - x->boid[theBoid].neighborDistSqr[j] = x->boid[theBoid].neighborDistSqr[j - 1]; - x->boid[theBoid].neighbor[j] = x->boid[theBoid].neighbor[j - 1]; - j--; - } - x->boid[theBoid].neighborDistSqr[j] = distSqr; - x->boid[theBoid].neighbor[j] = i; - } - } - } - } - - /*********************************/ - /* Match and avoid the neighbors */ - /*********************************/ - - matchNeighborVel->x = 0; - matchNeighborVel->y = 0; - // matchNeighborVel->z = 0; - - // set tempSpeed to old speed - tempSpeed = x->boid[theBoid].speed; - - for (i = 0; i < x->numNeighbors; i++) { - neighbor = x->boid[theBoid].neighbor[i]; - - // calculate matchNeighborVel by averaging the neighbor velocities - matchNeighborVel->x += x->boid[neighbor].oldDir.x; - matchNeighborVel->y += x->boid[neighbor].oldDir.y; - // matchNeighborVel->z += x->boid[neighbor].oldDir.z; - - // if distance is less than preferred distance, then neighbor influences boid - distSqr = x->boid[theBoid].neighborDistSqr[i]; - if (distSqr < x->prefDistSqr) { - dist = sqrt(distSqr); - - distH = x->boid[neighbor].oldPos.x - x->boid[theBoid].oldPos.x; - distV = x->boid[neighbor].oldPos.y - x->boid[theBoid].oldPos.y; - // distD = x->boid[neighbor].oldPos.z - x->boid[theBoid].oldPos.z; - - if(dist == 0.0) dist = 0.0000001; - totalVel.x = totalVel.x - distH - (distH * ((float) x->prefDist / (dist))); - totalVel.y = totalVel.y - distV - (distV * ((float) x->prefDist / (dist))); - // totalVel.z = totalVel.z - distD - (distV * ((float) x->prefDist / (dist))); - - numClose++; - } - if (InFront(&(x->boid[theBoid]), &(x->boid[neighbor]))) { // adjust speed - if (distSqr < x->prefDistSqr) - tempSpeed /= (x->accelFactor / 100.0); - else - tempSpeed *= (x->accelFactor / 100.0); - } - else { - if (distSqr < x->prefDistSqr) - tempSpeed *= (x->accelFactor / 100.0); - else - tempSpeed /= (x->accelFactor / 100.0); - } - } - if (numClose) { - avoidNeighborVel->x = totalVel.x / numClose; - avoidNeighborVel->y = totalVel.y / numClose; - // avoidNeighborVel->z = totalVel.z / numClose; - NormalizeVelocity(matchNeighborVel); - } - else { - avoidNeighborVel->x = 0; - avoidNeighborVel->y = 0; - // avoidNeighborVel->z = 0; - } - return(tempSpeed); -} - - -Velocity SeekPoint(t_boids *x, short theBoid, Point2d seekPt) -{ - Velocity tempDir; - tempDir.x = seekPt.x - x->boid[theBoid].oldPos.x; - tempDir.y = seekPt.y - x->boid[theBoid].oldPos.y; - // tempDir.z = seekPt.z - x->boid[theBoid].oldPos.z; - NormalizeVelocity(&tempDir); - return(tempDir); -} - - -Velocity AvoidWalls(t_boids *x, short theBoid) -{ - Point2d testPoint; - Velocity tempVel = {0.0, 0.0};//, 0.0}; - - /* calculate test point in front of the nose of the boid */ - /* distance depends on the boid's speed and the avoid edge constant */ - testPoint.x = x->boid[theBoid].oldPos.x + x->boid[theBoid].oldDir.x * x->boid[theBoid].speed * x->edgeDist; - testPoint.y = x->boid[theBoid].oldPos.y + x->boid[theBoid].oldDir.y * x->boid[theBoid].speed * x->edgeDist; - // testPoint.z = x->boid[theBoid].oldPos.z + x->boid[theBoid].oldDir.z * x->boid[theBoid].speed * x->edgeDist; - - /* if test point is out of the left (right) side of x->flyRect, */ - /* return a positive (negative) horizontal velocity component */ - if (testPoint.x < x->flyRect.left) - tempVel.x = fabs(x->boid[theBoid].oldDir.x); - else if (testPoint.x > x->flyRect.right) - tempVel.x = - fabs(x->boid[theBoid].oldDir.x); - - /* same with top and bottom */ - if (testPoint.y < x->flyRect.top) - tempVel.y = fabs(x->boid[theBoid].oldDir.y); - else if (testPoint.y > x->flyRect.bottom) - tempVel.y = - fabs(x->boid[theBoid].oldDir.y); - - /* same with front and back - if (testPoint.z < x->flyRect.front) - tempVel.z = fabs(x->boid[theBoid].oldDir.z); - else if (testPoint.z > x->flyRect.back) - tempVel.z = - fabs(x->boid[theBoid].oldDir.z); - */ - - return(tempVel); -} - - -int InFront(BoidPtr theBoid, BoidPtr neighbor) -{ - float grad, intercept; - int result; - -/* - -Find the gradient and y-intercept of a line passing through theBoid's oldPos -perpendicular to its direction of motion. Another boid is in front of theBoid -if it is to the right or left of this linedepending on whether theBoid is moving -right or left. However, if theBoid is travelling vertically then just compare -their vertical coordinates. - -*/ - // xy plane - - // if theBoid is not travelling vertically... - if (theBoid->oldDir.x != 0) { - // calculate gradient of a line _perpendicular_ to its direction (hence the minus) - grad = -theBoid->oldDir.y / theBoid->oldDir.x; - - // calculate where this line hits the y axis (from y = mx + c) - intercept = theBoid->oldPos.y - (grad * theBoid->oldPos.x); - - /* compare the horizontal position of the neighbor boid with */ - /* the point on the line that has its vertical coordinate */ - if (neighbor->oldPos.x >= ((neighbor->oldPos.y - intercept) / grad)) { - /* return true if the first boid's horizontal movement is +ve */ - result = (theBoid->oldDir.x > 0); - - if (result==0) return 0; - else goto next; - - } else { - /* return true if the first boid's horizontal movement is +ve */ - result = (theBoid->oldDir.x < 0); - if (result==0) return 0; - else goto next; - } - } - /* else theBoid is travelling vertically, so just compare vertical coordinates */ - else if (theBoid->oldDir.y > 0) { - result = (neighbor->oldPos.y > theBoid->oldPos.y); - if (result==0){ - return 0; - }else{ - goto next; - } - }else{ - result = (neighbor->oldPos.y < theBoid->oldPos.y); - if (result==0){ - return 0; - } else { - goto next; - } - } -next: -/* - // yz plane - - // if theBoid is not travelling vertically... - if (theBoid->oldDir.y != 0) { - // calculate gradient of a line _perpendicular_ to its direction (hence the minus) - grad = -theBoid->oldDir.z / theBoid->oldDir.y; - - // calculate where this line hits the y axis (from y = mx + c) - intercept = theBoid->oldPos.z - (grad * theBoid->oldPos.y); - - // compare the horizontal position of the neighbor boid with - // the point on the line that has its vertical coordinate - if (neighbor->oldPos.y >= ((neighbor->oldPos.z - intercept) / grad)) { - // return true if the first boid's horizontal movement is +ve - result = (theBoid->oldDir.y > 0); - if (result==0){ - return 0; - }else{ - goto next2; - } - } else { - // return true if the first boid's horizontal movement is +ve - result = (theBoid->oldDir.y < 0); - if (result==0){ - return 0; - }else{ - goto next2; - } - } - } - // else theBoid is travelling vertically, so just compare vertical coordinates - else if (theBoid->oldDir.z > 0) { - result = (neighbor->oldPos.z > theBoid->oldPos.z); - if (result==0){ - return 0; - }else{ - goto next2; - } - }else{ - result = (neighbor->oldPos.z < theBoid->oldPos.z); - if (result==0){ - return 0; - }else{ - goto next2; - } - } -next2: */ - return 1; -} - -void NormalizeVelocity(Velocity *direction) -{ - float my_hypot; - - my_hypot = sqrt(direction->x * direction->x + direction->y * direction->y);// + direction->z * direction->z ); - - if (my_hypot != 0.0) { - direction->x = direction->x / my_hypot; - direction->y = direction->y / my_hypot; - // direction->z = direction->z / my_hypot; - } -} - -double RandomInt(double minRange, double maxRange) -{ - unsigned short qdRdm; - double t, result; - - qdRdm = rand(); - t = (double)qdRdm / 65536.0; // now 0 <= t <= 1 - result = (t * (maxRange - minRange)) + minRange; - return(result); -} - -double DistSqrToPt(Point2d firstPoint, Point2d secondPoint) -{ - double a, b,c; - a = firstPoint.x - secondPoint.x; - b = firstPoint.y - secondPoint.y; - //c = firstPoint.z - secondPoint.z; - return(a * a + b * b); // + c * c); -} diff --git a/boids3d-help.pd b/boids3d-help.pd deleted file mode 100644 index 1324618..0000000 --- a/boids3d-help.pd +++ /dev/null @@ -1,297 +0,0 @@ -#N canvas 625 11 988 743 10; -#X declare -lib Gem; -#X msg 121 611 dump; -#X msg 121 630 reset; -#X floatatom 487 566 5 0 0 0 - \$0-flyrect0 - 0; -#X floatatom 526 566 5 0 0 0 - \$0-flyrect1 - 0; -#X floatatom 565 566 5 0 0 0 - \$0-flyrect2 - 0; -#X floatatom 604 566 5 0 0 0 - - - 0; -#X floatatom 486 625 5 0 0 0 - - - 0; -#X floatatom 526 625 5 0 0 0 - - - 0; -#X floatatom 121 577 5 0 0 0 - - - 0; -#X msg 121 592 mode \$1; -#X text 185 592 output mode; -#X text 185 611 parameter dump; -#X text 184 631 reset boids randomly inside flyrect; -#X text 29 94 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); -#X text 29 136 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; -#X text 29 169 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; -#X text 30 292 The flight parameters can be changed with messages. Use the 'dump' message to output a list of the current parameter settings.; -#X text 30 338 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; -#X text 32 74 arguments: number of boids \, output mode; -#X obj 148 470 print dump; -#X obj 17 19 cnv 15 800 48 empty empty boids3d 20 12 2 24 #dce0c8 #404040 0; -#X obj 69 420 bng 15 250 50 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000; -#N canvas 628 28 488 387 gem_example 0; -#X msg 33 31 destroy; -#N canvas 494 140 629 324 gemwin 0; -#X obj 219 190 gemwin; -#X obj 66 194 outlet; -#X obj 67 10 inlet; -#X obj 67 41 route create; -#X msg 67 70 set destroy; -#X msg 157 70 set create; -#X msg 350 115 destroy \, reset; -#X obj 157 38 loadbang; -#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.5; -#X msg 238 71 color 1 1 1; -#X connect 2 0 3 0; -#X connect 3 0 4 0; -#X connect 3 0 8 0; -#X connect 3 1 5 0; -#X connect 3 1 6 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X connect 6 0 0 0; -#X connect 7 0 5 0; -#X connect 8 0 0 0; -#X connect 9 0 0 0; -#X restore 33 51 pd gemwin; -#X obj 33 91 tgl 15 0 empty empty start_flocking_animation 20 6 1 10 #fcfcfc #000000 #000000 0 1; -#X obj 33 112 metro 33; -#X floatatom 33 234 5 0 0 0 - - - 0; -#X floatatom 84 234 5 0 0 0 - - - 0; -#X text 96 30 create/destroy OpenGl context; -#X obj 33 181 spigot; -#X obj 69 160 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 0 1; -#X obj 291 44 loadbang; -#X obj 33 287 pack 0 0 0; -#X msg 85 315 attractpt \$1 \$2 \$3; -#N canvas 0 22 414 375 center 0; -#X obj 101 37 gemhead; -#X obj 99 201 translateXYZ; -#X obj 124 166 unpack 0 0 0; -#X obj 147 94 inlet; -#X msg 240 193 draw line; -#X obj 252 106 loadbang; -#X obj 100 131 alpha; -#X obj 101 68 color 1 0.5 0 0.5; -#X obj 99 228 circle 0.1; -#X connect 0 0 7 0; -#X connect 1 0 8 0; -#X connect 2 0 1 1; -#X connect 2 1 1 2; -#X connect 2 2 1 3; -#X connect 3 0 2 0; -#X connect 4 0 8 0; -#X connect 5 0 4 0; -#X connect 6 0 1 0; -#X connect 7 0 6 0; -#X restore 33 362 pd center; -#X obj 205 163 boids3d 40; -#N canvas 0 22 466 396 orbit 0; -#X floatatom 103 160 5 0 0 0 - - - 0; -#X obj 103 187 expr $f1 * (3.141593/180.); -#X obj 103 45 inlet; -#X obj 166 314 outlet; -#X obj 103 314 outlet; -#N canvas 0 0 450 300 pol2cart 0; -#X obj 79 42 inlet r; -#X obj 159 42 inlet phi; -#X obj 79 231 outlet x; -#X obj 146 231 outlet y; -#X obj 146 120 t f f; -#X obj 146 144 cos; -#X obj 176 144 sin; -#X obj 79 171 t f f, f 10; -#X obj 79 197 * 1; -#X obj 146 196 * 0; -#X obj 79 93 unpack 0 0; -#X obj 79 65 pack \$1 \$2; -#X connect 0 0 11 0; -#X connect 1 0 11 1; -#X connect 4 0 5 0; -#X connect 4 1 6 0; -#X connect 5 0 8 1; -#X connect 6 0 9 1; -#X connect 7 0 8 0; -#X connect 7 1 9 0; -#X connect 8 0 2 0; -#X connect 9 0 3 0; -#X connect 10 0 7 0; -#X connect 10 1 4 0; -#X connect 11 0 10 0; -#X restore 103 254 pd pol2cart; -#X msg 103 210 1.5 \$1; -#X obj 103 277 swap, f 11; -#X obj 103 68 i; -#X obj 103 91 + 1; -#X obj 103 114 % 360; -#X obj 103 137 t f f; -#X connect 0 0 1 0; -#X connect 1 0 6 0; -#X connect 2 0 8 0; -#X connect 5 0 7 0; -#X connect 5 1 7 1; -#X connect 6 0 5 0; -#X connect 7 0 4 0; -#X connect 7 1 3 0; -#X connect 8 0 9 0; -#X connect 9 0 10 0; -#X connect 10 0 11 0; -#X connect 11 0 0 0; -#X connect 11 1 8 1; -#X restore 33 205 pd orbit; -#X obj 33 256 t f f; -#X obj 86 338 s \$0-boidParam; -#X obj 318 164 s \$0-init; -#X obj 205 190 clone -x 40 examples/gemboid \$0; -#X msg 291 67 1; -#X obj 291 90 t f b; -#X obj 205 135 r \$0-boidParam; -#X connect 0 0 1 0; -#X connect 1 0 0 0; -#X connect 2 0 3 0; -#X connect 3 0 7 0; -#X connect 3 0 13 0; -#X connect 4 0 15 0; -#X connect 5 0 10 1; -#X connect 7 0 14 0; -#X connect 8 0 7 1; -#X connect 9 0 19 0; -#X connect 10 0 12 0; -#X connect 10 0 11 0; -#X connect 11 0 16 0; -#X connect 13 0 18 0; -#X connect 14 0 4 0; -#X connect 14 1 5 0; -#X connect 15 0 10 2; -#X connect 15 1 10 0; -#X connect 19 0 20 0; -#X connect 20 0 8 0; -#X connect 20 1 17 0; -#X connect 21 0 13 0; -#X restore 277 440 pd gem_example; -#X msg 486 602 flyrect \$1 \$2 \$3 \$4 \$5 \$6; -#X text 612 585 bounding box (walls) in which to fly (l/t/r/b/f/b); -#X text 609 624 point to which boids are attracted (x/y/z); -#X obj 486 584 pack 0 0 0 0 0 0; -#X floatatom 643 566 5 0 0 0 - - - 0; -#X floatatom 682 566 5 0 0 0 - - - 0; -#X obj 69 498 print boids3d; -#X msg 486 662 attractpt \$1 \$2 \$3; -#X obj 486 642 pack 0 0 0; -#X floatatom 565 625 5 0 0 0 - - - 0; -#X text 30 115 float/2d/3d adaptation 08/2005 by a. sier / jasch; -#N canvas 67 162 494 344 META 0; -#X text 12 165 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; -#X text 12 145 AUTHOR Eric L. Singer; -#X text 12 5 KEYWORDS control; -#X text 12 45 DESCRIPTION bird flight and animal flock simulator; -#X text 12 65 INLET_0 bang mode dump reset number neighbors maxspeed minspeed center attract match avoid repel edgedist speed inertia accel prefdist flyrect attractpt; -#X text 12 105 OUTLET_0 list; -#X text 12 125 OUTLET_1 list; -#X text 12 25 LICENSE GPL v2; -#X restore 930 684 pd META; -#X obj 69 448 boids3d 16 0; -#X text 29 218 Boids takes an integer argument which is the number of boids. Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the coordinates for each boid \, the number and type depending on the mode.; -#X obj 824 20 declare -lib Gem; -#X obj 95 421 r \$0-boidParam; -#X obj 121 651 s \$0-boidParam; -#X obj 486 686 s \$0-boidParam; -#X msg 486 113 neighbors \$1; -#X floatatom 446 96 5 0 4 0 - \$0-neighbors - 0; -#X floatatom 446 131 5 0 0 0 - \$0-maxspeed - 0; -#X msg 486 148 maxspeed \$1; -#X floatatom 446 166 5 0 0 0 - \$0-minspeed - 0; -#X msg 486 183 minspeed \$1; -#X floatatom 446 201 5 0 0 0 - \$0-center - 0; -#X msg 486 218 center \$1; -#X floatatom 446 236 5 0 0 0 - \$0-attract - 0; -#X msg 486 253 attract \$1; -#X floatatom 446 271 5 0 0 0 - \$0-match - 0; -#X msg 486 288 match \$1; -#X floatatom 446 306 5 0 0 0 - \$0-avoid - 0; -#X msg 486 323 avoid \$1; -#X floatatom 446 341 5 0 0 0 - \$0-repel - 0; -#X msg 486 358 repel \$1; -#X floatatom 446 376 5 0 0 0 - \$0-edgedist - 0; -#X msg 486 393 edgedist \$1; -#X floatatom 446 411 5 0 0 0 - \$0-speed - 0; -#X msg 486 428 speed \$1; -#X floatatom 446 446 5 0 0 0 - \$0-inertia - 0; -#X msg 486 463 inertia \$1; -#X floatatom 446 481 5 0 0 0 - \$0-accel - 0; -#X msg 486 498 accel \$1; -#X floatatom 446 516 5 0 0 0 - \$0-prefdist - 0; -#X msg 486 533 prefdist \$1; -#X text 577 148 maximum speed of speed range; -#X text 579 182 minimum speed of speed range; -#X text 576 217 strength of centering instinct; -#X text 578 428 overall speed; -#X text 579 499 speed of acceleration; -#X text 579 530 preferred distance from neighbors; -#X floatatom 446 61 5 0 0 0 - \$0-number - 0; -#X msg 486 78 number \$1; -#X text 577 76 number of boids; -#X text 577 111 number of neighbors each boid consults when flocking; -#X text 576 288 strength of neighbor speed matching instinct; -#X text 576 323 strength of neighbor avoidance instinct; -#X text 576 355 strength of wall avoidance instinct; -#X text 578 391 distance of vision for avoiding wall edges; -#X text 579 462 willingness to change speed and direction; -#X text 575 251 strength of attraction to 'attractpt'; -#N canvas 1146 116 222 383 init 0; -#X obj 34 21 loadbang; -#X obj 17 79 b; -#X obj 17 112 list prepend \$0; -#X msg 17 145 \; \$1-neighbors 4 \; \$1-maxspeed 1.5 \; \$1-minspeed 1.2 \; \$1-center 1.2 \; \$1-attract 1.25 \; \$1-match 0.3 \; \$1-avoid 3.5 \; \$1-repel 3.5 \; \$1-edgedist 3 \; \$1-speed 3 \; \$1-inertia 4.5 \; \$1-accel 2.5 \; \$1-prefdist 1.5, f 17; -#X obj 94 21 r \$0-reset; -#X obj 111 52 inlet; -#X connect 0 0 1 0; -#X connect 1 0 2 0; -#X connect 2 0 3 0; -#X connect 4 0 1 0; -#X connect 5 0 1 0; -#X restore 277 407 pd init; -#X obj 277 387 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; -#X connect 0 0 39 0; -#X connect 1 0 39 0; -#X connect 2 0 26 0; -#X connect 3 0 26 1; -#X connect 4 0 26 2; -#X connect 5 0 26 3; -#X connect 6 0 31 0; -#X connect 7 0 31 1; -#X connect 8 0 9 0; -#X connect 9 0 39 0; -#X connect 21 0 35 0; -#X connect 23 0 40 0; -#X connect 26 0 23 0; -#X connect 27 0 26 4; -#X connect 28 0 26 5; -#X connect 30 0 40 0; -#X connect 31 0 30 0; -#X connect 32 0 31 2; -#X connect 35 0 29 0; -#X connect 35 1 19 0; -#X connect 38 0 35 0; -#X connect 41 0 40 0; -#X connect 42 0 41 0; -#X connect 43 0 44 0; -#X connect 44 0 40 0; -#X connect 45 0 46 0; -#X connect 46 0 40 0; -#X connect 47 0 48 0; -#X connect 48 0 40 0; -#X connect 49 0 50 0; -#X connect 50 0 40 0; -#X connect 51 0 52 0; -#X connect 52 0 40 0; -#X connect 53 0 54 0; -#X connect 54 0 40 0; -#X connect 55 0 56 0; -#X connect 56 0 40 0; -#X connect 57 0 58 0; -#X connect 58 0 40 0; -#X connect 59 0 60 0; -#X connect 60 0 40 0; -#X connect 61 0 62 0; -#X connect 62 0 40 0; -#X connect 63 0 64 0; -#X connect 64 0 40 0; -#X connect 65 0 66 0; -#X connect 66 0 40 0; -#X connect 73 0 74 0; -#X connect 74 0 40 0; -#X connect 84 0 83 0; diff --git a/boids3d.c b/boids3d.c deleted file mode 100644 index 9e57be3..0000000 --- a/boids3d.c +++ /dev/null @@ -1,956 +0,0 @@ -/* - - boids3d 2005 - 2006 a.sier / jasch - adapted from boids by eric singer © 1995-2003 eric l. singer - - 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 -*/ - -#include "m_pd.h" -#include -#include - -// constants -#define kAssistInlet 1 -#define kAssistOutlet 2 -#define kMaxLong 0xFFFFFFFF -#define kMaxNeighbors 4 - -// util -#define MAX(a,b) ((a)>(b)?(a):(b)) -#define CLIP(x,a,b) (x)=(x)<(a)?(a):(x)>(b)?(b):(x) - -// initial flight parameters -const short kNumBoids = 12; // number of boids -const short kNumNeighbors = 2; // must be <= kMaxNeighbors -const double kMinSpeed = 0.15; // boids' minimum speed -const double kMaxSpeed = 0.25; // boids' maximum speed -const double kCenterWeight = 0.25; // flock centering -const double kAttractWeight = 0.300;// attraction point seeking -const double kMatchWeight = 0.100;// neighbors velocity matching -const double kAvoidWeight = 0.10; // neighbors avoidance -const double kWallsWeight = 0.500;// wall avoidance [210] -const double kEdgeDist = 0.5; // vision distance to avoid wall edges [5] -const double kSpeedupFactor = 0.100;// alter animation speed -const double kInertiaFactor = 0.20; // willingness to change speed & direction -const double kAccelFactor = 0.100;// neighbor avoidance accelerate or decelerate rate -const double kPrefDist = 0.25; // preferred distance from neighbors -const double kFlyRectTop = 1.0; // fly rect boundaries -const double kFlyRectLeft = -1.0; -const double kFlyRectBottom = -1.0; -const double kFlyRectRight = 1.0; -const double kFlyRectFront = 1.0; -const double kFlyRectBack = -1.0; - - -// typedefs -typedef struct Velocity { - double x; - double y; - double z; -} Velocity; - -typedef struct Point3d { - double x; - double y; - double z; -} Point3d; - -typedef struct Box3D { - double left, right; - double top, bottom; - double front, back; -} Box3D; - -typedef struct _Boid { - Point3d oldPos; - Point3d newPos; - Velocity oldDir; - Velocity newDir; - double speed; - short neighbor[kMaxNeighbors]; - double neighborDistSqr[kMaxNeighbors]; -} t_one_boid, *BoidPtr; - -typedef struct _FlockObject { - t_object ob; - void *out1, *out2; - short mode; - long numBoids; - long numNeighbors; - Box3D flyRect; - double minSpeed; - double maxSpeed; - double centerWeight; - double attractWeight; - double matchWeight; - double avoidWeight; - double wallsWeight; - double edgeDist; - double speedupFactor; - double inertiaFactor; - double accelFactor; - double prefDist; - double prefDistSqr; - Point3d centerPt; - Point3d attractPt; - BoidPtr boid; - double d2r, r2d; -} t_boids, *FlockPtr; - - -t_symbol *ps_nothing; - -void *boids3d_class; -void *Flock_new(t_symbol *s, long argc, t_atom *argv); -void Flock_free(t_boids *x); -void Flock_bang(t_boids *x); -void Flock_dump(t_boids *x); -void Flock_mode(t_boids *x, t_float arg); -void Flock_numNeighbors(t_boids *x, t_float arg); -void Flock_numBoids(t_boids *x, t_float arg); -void Flock_minSpeed(t_boids *x, t_float arg); -void Flock_maxSpeed(t_boids *x, t_float arg); -void Flock_centerWeight(t_boids *x, t_float arg); -void Flock_attractWeight(t_boids *x, t_float arg); -void Flock_matchWeight(t_boids *x, t_float arg); -void Flock_avoidWeight(t_boids *x, t_float arg); -void Flock_wallsWeight(t_boids *x, t_float arg); -void Flock_edgeDist(t_boids *x, t_float arg); -void Flock_speedupFactor(t_boids *x, t_float arg); -void Flock_inertiaFactor(t_boids *x, t_float arg); -void Flock_accelFactor(t_boids *x, t_float arg); -void Flock_prefDist(t_boids *x, t_float arg); -void Flock_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv); -void Flock_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv); -void Flock_reset(t_boids *x); -void Flock_resetBoids(t_boids *x); -void InitFlock(t_boids *x); -void FlightStep(t_boids *x); -Point3d FindFlockCenter(t_boids *x); -float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborVel, Velocity *avoidNeighborVel); -Velocity SeekPoint(t_boids *x, short theBoid, Point3d seekPt); -Velocity AvoidWalls(t_boids *x, short theBoid); -int InFront(BoidPtr theBoid, BoidPtr neighbor); -void NormalizeVelocity(Velocity *direction); -double RandomInt(double minRange, double maxRange); -double DistSqrToPt(Point3d firstPoint, Point3d secondPoint); - -void boids3d_setup(void) -{ - boids3d_class = class_new(gensym("boids3d"), (t_newmethod)Flock_new, - (t_method)Flock_free, sizeof(t_boids), 0, A_GIMME, 0); - class_addfloat(boids3d_class, (t_method) Flock_numBoids); - class_addbang(boids3d_class, (t_method) Flock_bang); - class_addmethod(boids3d_class, (t_method) Flock_numNeighbors, gensym("neighbors"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_numBoids, gensym("number"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_mode, gensym("mode"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_minSpeed, gensym("minspeed"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_maxSpeed, gensym("maxspeed"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_centerWeight, gensym("center"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_attractWeight, gensym("attract"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_matchWeight, gensym("match"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_avoidWeight, gensym("avoid"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_wallsWeight, gensym("repel"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_edgeDist, gensym("edgedist"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_speedupFactor, gensym("speed"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_inertiaFactor, gensym("inertia"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_accelFactor, gensym("accel"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_prefDist, gensym("prefdist"), A_FLOAT, 0); - class_addmethod(boids3d_class, (t_method) Flock_flyRect, gensym("flyrect"), A_GIMME, 0); - class_addmethod(boids3d_class, (t_method) Flock_attractPt, gensym("attractpt"), A_GIMME, 0); - class_addmethod(boids3d_class, (t_method) Flock_resetBoids, gensym("reset"), 0); - class_addmethod(boids3d_class, (t_method) Flock_reset, gensym("init"), 0); - class_addmethod(boids3d_class, (t_method) Flock_dump, gensym("dump"), 0); - - logpost(NULL, 4, "boids3d 2005-2006 a.sier / jasch © 1995-2003 eric l. singer "__DATE__" "__TIME__); - ps_nothing = gensym(""); -} - - -void *Flock_new(t_symbol *s, long argc, t_atom *argv) -{ - t_boids *x = (t_boids *)pd_new(boids3d_class); - x->out1 = outlet_new(&x->ob, NULL); - x->out2 = outlet_new(&x->ob, NULL); - - x->numBoids = 16; - if((argc >= 1) && (argv[0].a_type == A_FLOAT)){ - x->numBoids = argv[0].a_w.w_float; - } - x->boid = (t_one_boid *)malloc(sizeof(t_one_boid) * x->numBoids); - - InitFlock(x); - - x->mode = 0; - if((argc >= 2) && (argv[1].a_type == A_FLOAT)){ - x->mode = (short)(CLIP(argv[1].a_w.w_float, 0, 2)); - } - - x->d2r = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068/180.0; - x->r2d = 180.0/3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068; - - return(x); -} - -void Flock_free(t_boids *x) -{ - free(x->boid); -} - -void Flock_bang(t_boids *x) -{ - short i; - t_atom outlist[10]; - t_atom *out; - - double tempNew_x, tempNew_y, tempNew_z; - double tempOld_x, tempOld_y, tempOld_z; - double delta_x, delta_y, delta_z; - double azi, ele, speed; - - out = outlist; - - FlightStep(x); - - - switch(x->mode) { // newpos - case 0: - for (i = 0; i < x->numBoids; i++){ - SETFLOAT(out+0, i); - SETFLOAT(out+1, x->boid[i].newPos.x); - SETFLOAT(out+2, x->boid[i].newPos.y); - SETFLOAT(out+3, x->boid[i].newPos.z); - outlet_list(x->out1, 0L, 4, out); - } - break; - case 1: //newpos + oldpos - for (i = 0; i < x->numBoids; i++){ - SETFLOAT(out+0, i); - SETFLOAT(out+1, x->boid[i].newPos.x); - SETFLOAT(out+2, x->boid[i].newPos.y); - SETFLOAT(out+3, x->boid[i].newPos.z); - SETFLOAT(out+4, x->boid[i].oldPos.x); - SETFLOAT(out+5, x->boid[i].oldPos.y); - SETFLOAT(out+6, x->boid[i].oldPos.z); - outlet_list(x->out1, 0L, 7, out); - } - break; - case 2: - for (i = 0; i < x->numBoids; i++){ - tempNew_x = x->boid[i].newPos.x; - tempNew_y = x->boid[i].newPos.y; - tempNew_z = x->boid[i].newPos.z; - tempOld_x = x->boid[i].oldPos.x; - tempOld_y = x->boid[i].oldPos.y; - tempOld_z = x->boid[i].oldPos.z; - delta_x = tempNew_x - tempOld_x; - delta_y = tempNew_y - tempOld_y; - delta_z = tempNew_z - tempOld_z; - azi = atan2(delta_y, delta_x) * x->r2d; - ele = atan2(delta_y, delta_x) * x->r2d; - speed = sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z); - SETFLOAT(out+0, i); - SETFLOAT(out+1, tempNew_x); - SETFLOAT(out+2, tempNew_y); - SETFLOAT(out+3, tempNew_z); - SETFLOAT(out+4, tempOld_x); - SETFLOAT(out+5, tempOld_y); - SETFLOAT(out+6, tempOld_z); - SETFLOAT(out+7, speed); - SETFLOAT(out+8, azi); - SETFLOAT(out+9, ele); - outlet_list(x->out1, 0L, 10, out); - } - break; - } -} - -void Flock_dump(t_boids *x) -{ - t_atom outList[6]; - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->numNeighbors; - outlet_anything(x->out2, gensym("neighbors"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->minSpeed; - outlet_anything(x->out2, gensym("minspeed"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->maxSpeed; - outlet_anything(x->out2, gensym("maxspeed"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->centerWeight; - outlet_anything(x->out2, gensym("center"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->attractWeight; - outlet_anything(x->out2, gensym("attract"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->matchWeight; - outlet_anything(x->out2, gensym("match"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->avoidWeight; - outlet_anything(x->out2, gensym("avoid"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->wallsWeight; - outlet_anything(x->out2, gensym("repel"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->edgeDist; - outlet_anything(x->out2, gensym("edgedist"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->speedupFactor; - outlet_anything(x->out2, gensym("speed"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->inertiaFactor; - outlet_anything(x->out2, gensym("inertia"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->accelFactor; - outlet_anything(x->out2, gensym("accel"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->prefDist; - outlet_anything(x->out2, gensym("prefdist"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->flyRect.left; - outList[1].a_type = A_FLOAT; - outList[1].a_w.w_float = x->flyRect.top; - outList[2].a_type = A_FLOAT; - outList[2].a_w.w_float = x->flyRect.right; - outList[3].a_type = A_FLOAT; - outList[3].a_w.w_float = x->flyRect.bottom; - outList[4].a_type = A_FLOAT; - outList[4].a_w.w_float = x->flyRect.front; - outList[5].a_type = A_FLOAT; - outList[5].a_w.w_float = x->flyRect.back; - outlet_anything(x->out2, gensym("flyrect"), 6, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->attractPt.x; - outList[1].a_type = A_FLOAT; - outList[1].a_w.w_float = x->attractPt.y; - outList[2].a_type = A_FLOAT; - outList[2].a_w.w_float = x->attractPt.z; - outlet_anything(x->out2, gensym("attractpt"), 3, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->mode; - outlet_anything(x->out2, gensym("mode"), 1, outList); - - outList[0].a_type = A_FLOAT; - outList[0].a_w.w_float = x->numBoids; - outlet_anything(x->out2, gensym("number"), 1, outList); -} - - -void Flock_mode(t_boids *x, t_float arg) -{ - long m = (long)arg; - x->mode = CLIP(m, 0, 2); -} - -void Flock_numNeighbors(t_boids *x, t_float arg) -{ - x->numNeighbors = (long)arg; -} - -void Flock_numBoids(t_boids *x, t_float arg) -{ - x->boid = (t_one_boid *)realloc(x->boid, sizeof(t_one_boid) * (long)arg); - x->numBoids = (long)arg; - Flock_resetBoids(x); -} - -void Flock_minSpeed(t_boids *x, t_float arg) -{ - x->minSpeed = MAX(arg, 0.000001); -} - -void Flock_maxSpeed(t_boids *x, t_float arg) -{ - x->maxSpeed = (double)arg; -} - -void Flock_centerWeight(t_boids *x, t_float arg) -{ - x->centerWeight = (double)arg; -} - -void Flock_attractWeight(t_boids *x, t_float arg) -{ - x->attractWeight = (double)arg; -} - -void Flock_matchWeight(t_boids *x, t_float arg) -{ - x->matchWeight = (double)arg; -} - -void Flock_avoidWeight(t_boids *x, t_float arg) -{ - x->avoidWeight = (double)arg; -} - -void Flock_wallsWeight(t_boids *x, t_float arg) -{ - x->wallsWeight = (double)arg; -} - -void Flock_edgeDist(t_boids *x, t_float arg) -{ - x->edgeDist = (double)arg; -} - -void Flock_speedupFactor(t_boids *x, t_float arg) -{ - x->speedupFactor = (double)arg; -} - -void Flock_inertiaFactor(t_boids *x, t_float arg) -{ - if(arg == 0){ - x->inertiaFactor = 0.000001; - }else{ - x->inertiaFactor = (double)arg; - } -} - -void Flock_accelFactor(t_boids *x, t_float arg) -{ - x->accelFactor = (double)arg; -} - -void Flock_prefDist(t_boids *x, t_float arg) -{ - x->prefDist = (double)arg; -} - -void Flock_flyRect(t_boids *x, t_symbol *msg, short argc, t_atom *argv) -{ - double temp[6]; - short i; - if(argc == 6){ - for(i = 0; i < 6; i++) { - if(argv[i].a_type == A_FLOAT) { - temp[i] = (double)argv[i].a_w.w_float; - } - } - x->flyRect.left = temp[0]; - x->flyRect.top = temp[1]; - x->flyRect.right = temp[2]; - x->flyRect.bottom = temp[3]; - x->flyRect.front = temp[4]; - x->flyRect.back = temp[5]; - }else{ - pd_error(x, "boids3d: flyrect needs 6 values"); - } -} - -void Flock_attractPt(t_boids *x, t_symbol *msg, short argc, t_atom *argv) -{ - double temp[3]; - short i; - if(argc == 3){ - for(i = 0; i < 3 ; i++) { - if(argv[i].a_type == A_FLOAT) { - temp[i] = (double)argv[i].a_w.w_float; - } - } - x->attractPt.x = temp[0]; - x->attractPt.y = temp[1]; - x->attractPt.z = temp[2]; - }else{ - pd_error(x, "boids3d: attractPt needs 3 values"); - } -} - -void Flock_reset(t_boids *x) -{ - InitFlock(x); -} - -void Flock_resetBoids(t_boids *x) -{ - long i, j; - double rndAngle; - - for (i = 0; i < x->numBoids; i++) { // init everything to 0.0 - x->boid[i].oldPos.x = 0.0; - x->boid[i].oldPos.y = 0.0; - x->boid[i].oldPos.z = 0.0; - - x->boid[i].newPos.x = 0.0; - x->boid[i].newPos.y = 0.0; - x->boid[i].newPos.z = 0.0; - - x->boid[i].oldDir.x = 0.0; - x->boid[i].oldDir.y = 0.0; - x->boid[i].oldDir.z = 0.0; - - x->boid[i].newDir.x = 0.0; - x->boid[i].newDir.y = 0.0; - x->boid[i].newDir.z = 0.0; - - x->boid[i].speed = 0.0; - - for(j=0; jboid[i].neighbor[j] = 0; - x->boid[i].neighborDistSqr[j] = 0.0; - } - } - for (i = 0; i < x->numBoids; i++) { // set the initial locations and velocities of the boids - x->boid[i].newPos.x = x->boid[i].oldPos.x = RandomInt(x->flyRect.right,x->flyRect.left); // set random location within flyRect - x->boid[i].newPos.y = x->boid[i].oldPos.y = RandomInt(x->flyRect.bottom, x->flyRect.top); - x->boid[i].newPos.z = x->boid[i].oldPos.z = RandomInt(x->flyRect.back, x->flyRect.front); - rndAngle = RandomInt(0, 360) * x->d2r; // set velocity from random angle - x->boid[i].newDir.x = sin(rndAngle); - x->boid[i].newDir.y = cos(rndAngle); - x->boid[i].newDir.z = (cos(rndAngle) + sin(rndAngle)) * 0.5; - x->boid[i].speed = (kMaxSpeed + kMinSpeed) * 0.5; - } -} - -void InitFlock(t_boids *x) -{ - x->numNeighbors = kNumNeighbors; - x->minSpeed = kMinSpeed; - x->maxSpeed = kMaxSpeed; - x->centerWeight = kCenterWeight; - x->attractWeight = kAttractWeight; - x->matchWeight = kMatchWeight; - x->avoidWeight = kAvoidWeight; - x->wallsWeight = kWallsWeight; - x->edgeDist = kEdgeDist; - x->speedupFactor = kSpeedupFactor; - x->inertiaFactor = kInertiaFactor; - x->accelFactor = kAccelFactor; - x->prefDist = kPrefDist; - x->prefDistSqr = kPrefDist * kPrefDist; - x->flyRect.top = kFlyRectTop; - x->flyRect.left = kFlyRectLeft; - x->flyRect.bottom = kFlyRectBottom; - x->flyRect.right = kFlyRectRight; - x->flyRect.front = kFlyRectFront; - x->flyRect.back = kFlyRectBack; - x->attractPt.x = (kFlyRectLeft + kFlyRectRight) * 0.5; - x->attractPt.y = (kFlyRectTop + kFlyRectBottom) * 0.5; - x->attractPt.z = (kFlyRectFront + kFlyRectBack) * 0.5; - Flock_resetBoids(x); -} - -void FlightStep(t_boids *x) -{ - Velocity goCenterVel; - Velocity goAttractVel; - Velocity matchNeighborVel; - Velocity avoidWallsVel; - Velocity avoidNeighborVel; - float avoidNeighborSpeed; - const Velocity zeroVel = {0.0, 0.0, 0.0}; - short i; - - x->centerPt = FindFlockCenter(x); - for (i = 0; i < x->numBoids; i++) { // save position and velocity - x->boid[i].oldPos.x = x->boid[i].newPos.x; - x->boid[i].oldPos.y = x->boid[i].newPos.y; - x->boid[i].oldPos.z = x->boid[i].newPos.z; - - x->boid[i].oldDir.x = x->boid[i].newDir.x; - x->boid[i].oldDir.y = x->boid[i].newDir.y; - x->boid[i].oldDir.z = x->boid[i].newDir.z; - } - for (i = 0; i < x->numBoids; i++) { - if (x->numNeighbors > 0) { // get all velocity components - avoidNeighborSpeed = MatchAndAvoidNeighbors(x, i,&matchNeighborVel, &avoidNeighborVel); - } else { - matchNeighborVel = zeroVel; - avoidNeighborVel = zeroVel; - avoidNeighborSpeed = 0; - } - goCenterVel = SeekPoint(x, i, x->centerPt); - goAttractVel = SeekPoint(x, i, x->attractPt); - avoidWallsVel = AvoidWalls(x, i); - - // compute resultant velocity using weights and inertia - x->boid[i].newDir.x = x->inertiaFactor * (x->boid[i].oldDir.x) + - (x->centerWeight * goCenterVel.x + - x->attractWeight * goAttractVel.x + - x->matchWeight * matchNeighborVel.x + - x->avoidWeight * avoidNeighborVel.x + - x->wallsWeight * avoidWallsVel.x) / x->inertiaFactor; - x->boid[i].newDir.y = x->inertiaFactor * (x->boid[i].oldDir.y) + - (x->centerWeight * goCenterVel.y + - x->attractWeight * goAttractVel.y + - x->matchWeight * matchNeighborVel.y + - x->avoidWeight * avoidNeighborVel.y + - x->wallsWeight * avoidWallsVel.y) / x->inertiaFactor; - x->boid[i].newDir.z = x->inertiaFactor * (x->boid[i].oldDir.z) + - (x->centerWeight * goCenterVel.z + - x->attractWeight * goAttractVel.z + - x->matchWeight * matchNeighborVel.z + - x->avoidWeight * avoidNeighborVel.z + - x->wallsWeight * avoidWallsVel.z) / x->inertiaFactor; - NormalizeVelocity(&(x->boid[i].newDir)); // normalize velocity so its length is unity - - // set to avoidNeighborSpeed bounded by minSpeed and maxSpeed - if ((avoidNeighborSpeed >= x->minSpeed) && - (avoidNeighborSpeed <= x->maxSpeed)) - x->boid[i].speed = avoidNeighborSpeed; - else if (avoidNeighborSpeed > x->maxSpeed) - x->boid[i].speed = x->maxSpeed; - else - x->boid[i].speed = x->minSpeed; - - // calculate new position, applying speedupFactor - x->boid[i].newPos.x += x->boid[i].newDir.x * x->boid[i].speed * (x->speedupFactor / 100.0); - x->boid[i].newPos.y += x->boid[i].newDir.y * x->boid[i].speed * (x->speedupFactor / 100.0); - x->boid[i].newPos.z += x->boid[i].newDir.z * x->boid[i].speed * (x->speedupFactor / 100.0); - - } -} - -Point3d FindFlockCenter(t_boids *x) -{ - double totalH = 0, totalV = 0, totalD = 0; - Point3d centerPoint; - register short i; - - for (i = 0 ; i < x->numBoids; i++) - { - totalH += x->boid[i].oldPos.x; - totalV += x->boid[i].oldPos.y; - totalD += x->boid[i].oldPos.z; - } - centerPoint.x = (double) (totalH / x->numBoids); - centerPoint.y = (double) (totalV / x->numBoids); - centerPoint.z = (double) (totalD / x->numBoids); - - return(centerPoint); -} - -float MatchAndAvoidNeighbors(t_boids *x, short theBoid, Velocity *matchNeighborVel, Velocity *avoidNeighborVel) -{ - short i, j, neighbor; - double distSqr; - double dist, distH, distV,distD; - double tempSpeed; - short numClose = 0; - Velocity totalVel = {0.0, 0.0, 0.0}; - - /**********************/ - /* Find the neighbors */ - /**********************/ - - /* special case of one neighbor */ - if (x->numNeighbors == 1) { - x->boid[theBoid].neighborDistSqr[0] = kMaxLong; - - for (i = 0; i < x->numBoids; i++) { - if (i != theBoid) { - distSqr = DistSqrToPt(x->boid[theBoid].oldPos, x->boid[i].oldPos); - - /* if this one is closer than the closest so far, then remember it */ - if (x->boid[theBoid].neighborDistSqr[0] > distSqr) { - x->boid[theBoid].neighborDistSqr[0] = distSqr; - x->boid[theBoid].neighbor[0] = i; - } - } - } - } - /* more than one neighbor */ - else { - for (j = 0; j < x->numNeighbors; j++) - x->boid[theBoid].neighborDistSqr[j] = kMaxLong; - - for (i = 0 ; i < x->numBoids; i++) { - /* if this one is not me... */ - if (i != theBoid) { - distSqr = DistSqrToPt(x->boid[theBoid].oldPos, x->boid[i].oldPos); - - /* if distSqr is less than the distance at the bottom of the array, sort into array */ - if (distSqr < x->boid[theBoid].neighborDistSqr[x->numNeighbors-1]) { - j = x->numNeighbors - 1; - - /* sort distSqr in to keep array in size order, smallest first */ - while ((distSqr < x->boid[theBoid].neighborDistSqr[j-1]) && (j > 0)) { - x->boid[theBoid].neighborDistSqr[j] = x->boid[theBoid].neighborDistSqr[j - 1]; - x->boid[theBoid].neighbor[j] = x->boid[theBoid].neighbor[j - 1]; - j--; - } - x->boid[theBoid].neighborDistSqr[j] = distSqr; - x->boid[theBoid].neighbor[j] = i; - } - } - } - } - - /*********************************/ - /* Match and avoid the neighbors */ - /*********************************/ - - matchNeighborVel->x = 0; - matchNeighborVel->y = 0; - matchNeighborVel->z = 0; - - // set tempSpeed to old speed - tempSpeed = x->boid[theBoid].speed; - - for (i = 0; i < x->numNeighbors; i++) { - neighbor = x->boid[theBoid].neighbor[i]; - - // calculate matchNeighborVel by averaging the neighbor velocities - matchNeighborVel->x += x->boid[neighbor].oldDir.x; - matchNeighborVel->y += x->boid[neighbor].oldDir.y; - matchNeighborVel->z += x->boid[neighbor].oldDir.z; - - // if distance is less than preferred distance, then neighbor influences boid - distSqr = x->boid[theBoid].neighborDistSqr[i]; - if (distSqr < x->prefDistSqr) { - dist = sqrt(distSqr); - - distH = x->boid[neighbor].oldPos.x - x->boid[theBoid].oldPos.x; - distV = x->boid[neighbor].oldPos.y - x->boid[theBoid].oldPos.y; - distD = x->boid[neighbor].oldPos.z - x->boid[theBoid].oldPos.z; - - if(dist == 0.0) dist = 0.0000001; - totalVel.x = totalVel.x - distH - (distH * ((float) x->prefDist / (dist))); - totalVel.y = totalVel.y - distV - (distV * ((float) x->prefDist / (dist))); - totalVel.z = totalVel.z - distD - (distV * ((float) x->prefDist / (dist))); - - numClose++; - } - if (InFront(&(x->boid[theBoid]), &(x->boid[neighbor]))) { // adjust speed - if (distSqr < x->prefDistSqr) - tempSpeed /= (x->accelFactor / 100.0); - else - tempSpeed *= (x->accelFactor / 100.0); - } - else { - if (distSqr < x->prefDistSqr) - tempSpeed *= (x->accelFactor / 100.0); - else - tempSpeed /= (x->accelFactor / 100.0); - } - } - if (numClose) { - avoidNeighborVel->x = totalVel.x / numClose; - avoidNeighborVel->y = totalVel.y / numClose; - avoidNeighborVel->z = totalVel.z / numClose; - NormalizeVelocity(matchNeighborVel); - } - else { - avoidNeighborVel->x = 0; - avoidNeighborVel->y = 0; - avoidNeighborVel->z = 0; - } - return(tempSpeed); -} - - -Velocity SeekPoint(t_boids *x, short theBoid, Point3d seekPt) -{ - Velocity tempDir; - tempDir.x = seekPt.x - x->boid[theBoid].oldPos.x; - tempDir.y = seekPt.y - x->boid[theBoid].oldPos.y; - tempDir.z = seekPt.z - x->boid[theBoid].oldPos.z; - NormalizeVelocity(&tempDir); - return(tempDir); -} - - -Velocity AvoidWalls(t_boids *x, short theBoid) -{ - Point3d testPoint; - Velocity tempVel = {0.0, 0.0, 0.0}; - - /* calculate test point in front of the nose of the boid */ - /* distance depends on the boid's speed and the avoid edge constant */ - testPoint.x = x->boid[theBoid].oldPos.x + x->boid[theBoid].oldDir.x * x->boid[theBoid].speed * x->edgeDist; - testPoint.y = x->boid[theBoid].oldPos.y + x->boid[theBoid].oldDir.y * x->boid[theBoid].speed * x->edgeDist; - testPoint.z = x->boid[theBoid].oldPos.z + x->boid[theBoid].oldDir.z * x->boid[theBoid].speed * x->edgeDist; - - /* if test point is out of the left (right) side of x->flyRect, */ - /* return a positive (negative) horizontal velocity component */ - if (testPoint.x < x->flyRect.left) - tempVel.x = fabs(x->boid[theBoid].oldDir.x); - else if (testPoint.x > x->flyRect.right) - tempVel.x = - fabs(x->boid[theBoid].oldDir.x); - - /* same with top and bottom */ - if (testPoint.y < x->flyRect.top) - tempVel.y = fabs(x->boid[theBoid].oldDir.y); - else if (testPoint.y > x->flyRect.bottom) - tempVel.y = - fabs(x->boid[theBoid].oldDir.y); - - /* same with front and back */ - if (testPoint.z < x->flyRect.front) - tempVel.z = fabs(x->boid[theBoid].oldDir.z); - else if (testPoint.z > x->flyRect.back) - tempVel.z = - fabs(x->boid[theBoid].oldDir.z); - - return(tempVel); -} - - -int InFront(BoidPtr theBoid, BoidPtr neighbor) -{ - float grad, intercept; - int result; - -/* - -Find the gradient and y-intercept of a line passing through theBoid's oldPos -perpendicular to its direction of motion. Another boid is in front of theBoid -if it is to the right or left of this linedepending on whether theBoid is moving -right or left. However, if theBoid is travelling vertically then just compare -their vertical coordinates. - -*/ - // xy plane - - // if theBoid is not travelling vertically... - if (theBoid->oldDir.x != 0) { - // calculate gradient of a line _perpendicular_ to its direction (hence the minus) - grad = -theBoid->oldDir.y / theBoid->oldDir.x; - - // calculate where this line hits the y axis (from y = mx + c) - intercept = theBoid->oldPos.y - (grad * theBoid->oldPos.x); - - /* compare the horizontal position of the neighbor boid with */ - /* the point on the line that has its vertical coordinate */ - if (neighbor->oldPos.x >= ((neighbor->oldPos.y - intercept) / grad)) { - /* return true if the first boid's horizontal movement is +ve */ - result = (theBoid->oldDir.x > 0); - - if (result==0) return 0; - else goto next; - - } else { - /* return true if the first boid's horizontal movement is +ve */ - result = (theBoid->oldDir.x < 0); - if (result==0) return 0; - else goto next; - } - } - /* else theBoid is travelling vertically, so just compare vertical coordinates */ - else if (theBoid->oldDir.y > 0) { - result = (neighbor->oldPos.y > theBoid->oldPos.y); - if (result==0){ - return 0; - }else{ - goto next; - } - }else{ - result = (neighbor->oldPos.y < theBoid->oldPos.y); - if (result==0){ - return 0; - } else { - goto next; - } - } -next: - // yz plane - - // if theBoid is not travelling vertically... - if (theBoid->oldDir.y != 0) { - // calculate gradient of a line _perpendicular_ to its direction (hence the minus) - grad = -theBoid->oldDir.z / theBoid->oldDir.y; - - // calculate where this line hits the y axis (from y = mx + c) - intercept = theBoid->oldPos.z - (grad * theBoid->oldPos.y); - - // compare the horizontal position of the neighbor boid with - // the point on the line that has its vertical coordinate - if (neighbor->oldPos.y >= ((neighbor->oldPos.z - intercept) / grad)) { - // return true if the first boid's horizontal movement is +ve - result = (theBoid->oldDir.y > 0); - if (result==0){ - return 0; - }else{ - goto next2; - } - } else { - // return true if the first boid's horizontal movement is +ve - result = (theBoid->oldDir.y < 0); - if (result==0){ - return 0; - }else{ - goto next2; - } - } - } - // else theBoid is travelling vertically, so just compare vertical coordinates - else if (theBoid->oldDir.z > 0) { - result = (neighbor->oldPos.z > theBoid->oldPos.z); - if (result==0){ - return 0; - }else{ - goto next2; - } - }else{ - result = (neighbor->oldPos.z < theBoid->oldPos.z); - if (result==0){ - return 0; - }else{ - goto next2; - } - } -next2: - return 1; -} - -void NormalizeVelocity(Velocity *direction) -{ - float my_hypot; - - my_hypot = sqrt(direction->x * direction->x + direction->y * direction->y + direction->z * direction->z ); - - if (my_hypot != 0.0) { - direction->x = direction->x / my_hypot; - direction->y = direction->y / my_hypot; - direction->z = direction->z / my_hypot; - } -} - -double RandomInt(double minRange, double maxRange) -{ - unsigned short qdRdm; - double t, result; - - qdRdm = rand(); - t = (double)qdRdm / 65536.0; // now 0 <= t <= 1 - result = (t * (maxRange - minRange)) + minRange; - return(result); -} - -double DistSqrToPt(Point3d firstPoint, Point3d secondPoint) -{ - double a, b,c; - a = firstPoint.x - secondPoint.x; - b = firstPoint.y - secondPoint.y; - c = firstPoint.z - secondPoint.z; - return(a * a + b * b + c * c); -} diff --git a/examples/boids-gem.pd b/examples/boids-gem.pd new file mode 100644 index 0000000..1eeaae5 --- /dev/null +++ b/examples/boids-gem.pd @@ -0,0 +1,424 @@ +#N canvas 741 52 738 578 12; +#X declare -lib Gem -lib boids -path boids; +#X msg 100 40 create; +#N canvas 803 136 629 324 gemwin 0; +#X obj 209 190 gemwin; +#X obj 67 194 outlet; +#X obj 67 10 inlet; +#X obj 67 41 route create; +#X msg 67 70 set destroy; +#X msg 157 70 set create; +#X msg 350 115 destroy \, reset; +#X obj 157 18 loadbang; +#X msg 238 71 color 1 1 1; +#X obj 496 28 gemhead; +#X obj 496 50 world_light; +#X msg 212 146 create \, 1 \, frame 30 \, color 0 0 0.5 \, lighting 1; +#X connect 2 0 3 0; +#X connect 3 0 4 0; +#X connect 3 0 11 0; +#X connect 3 1 5 0; +#X connect 3 1 6 0; +#X connect 4 0 1 0; +#X connect 5 0 1 0; +#X connect 6 0 0 0; +#X connect 7 0 5 0; +#X connect 8 0 0 0; +#X connect 9 0 10 0; +#X connect 11 0 0 0; +#X restore 100 60 pd gemwin; +#N canvas 319 40 953 920 orbit 0; +#X obj 97 624 translateXYZ; +#X obj 83 334 t a b; +#X obj 668 260 color 1 0.5 0 0.5; +#X obj 690 297 loadbang; +#X obj 668 232 gemhead 58; +#X msg 690 324 draw line; +#X obj 89 277 gemhead; +#X obj 89 48 inlet; +#X obj 674 405 cube 4; +#X obj 84 249 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 81 108 sel 0; +#X obj 720 374 r \$0-bounds; +#X msg 81 133 0 0 0; +#X obj 661 163 r \$0-vis-bounds; +#X obj 822 161 loadbang; +#X msg 822 186 0; +#X obj 329 27 boids-params \$0-2; +#A saved flyrect -2 2 -2 2; +#A saved dimensions 3; +#A saved number 3; +#A saved neighbors 2; +#A saved speed 2; +#A saved minspeed 4; +#A saved maxspeed 19; +#A saved inertia 1.08; +#A saved accel 1.29; +#A saved edgedist 2; +#A saved repel 5; +#A saved match 0.31; +#A saved avoid 1.39; +#A saved attract -1.84; +#A saved center 0.460001; +#A saved prefdist 5; +#X obj 338 311 list trim; +#X obj 674 849 pack f f f; +#X obj 646 578 spigot; +#X obj 700 578 spigot; +#X obj 706 524 t f f; +#X obj 675 483 gemmouse 1 1; +#A saved init; +#X obj 652 618 * 8; +#X obj 652 641 - 4; +#X obj 698 683 - 4; +#X text 724 632 invert y; +#X obj 698 660 * 8; +#X msg 698 601 1 \$1; +#X obj 698 625 -; +#X obj 805 680 spigot; +#X obj 805 705 t b f; +#X obj 714 552 t f f; +#X obj 809 632 * 8; +#X obj 810 654 - 4; +#X obj 673 875 s \$0-orbit-translation; +#X text 655 459 mouse interaction; +#X text 749 769 middle click to enable Z motion (up/down), f 19; +#X obj 235 451 route 0; +#X obj 233 512 s \$0-orbit-translation; +#X obj 239 423 boids; +#X obj 385 412 r \$0-mass-center; +#X msg 385 437 attractpt \$1 \$2 \$3; +#X obj 567 35 r \$0-bounds; +#X obj 567 60 s \$0-2-bounds-set; +#X msg 383 370 mode 2; +#X obj 128 581 unpack f f f; +#X obj 236 482 list split 3; +#X obj 309 655 list split 3; +#X obj 230 731 rotateXYZ; +#X obj 303 690 unpack f f f; +#X obj 219 772 sphere 0.3 3; +#X obj 374 347 loadbang; +#X obj 201 381 spigot 1; +#X obj 85 74 t f f; +#X obj 144 555 r \$0-orbit-translation; +#X obj 81 159 s \$0-orbit-translation; +#X text 676 99 see the bounding box; +#X text 80 213 move like a pray; +#X text 425 471 this boids has an attract point which is the mass center of the other flock. also \, the attract weight is set to negative \, so that it rejects this attract point whenever it can. Thus \, it may behave like a pray, f 18; +#X obj 90 304 color 1 0 0; +#X connect 0 0 49 0; +#X connect 1 0 0 0; +#X connect 1 1 53 0; +#X connect 2 0 8 0; +#X connect 3 0 5 0; +#X connect 4 0 2 0; +#X connect 5 0 8 0; +#X connect 6 0 60 0; +#X connect 7 0 54 0; +#X connect 9 0 6 0; +#X connect 10 0 12 0; +#X connect 11 0 8 1; +#X connect 12 0 56 0; +#X connect 13 0 4 0; +#X connect 14 0 15 0; +#X connect 15 0 4 0; +#X connect 16 0 17 0; +#X connect 17 0 40 0; +#X connect 18 0 35 0; +#X connect 19 0 23 0; +#X connect 20 0 28 0; +#X connect 21 0 19 1; +#X connect 21 1 20 1; +#X connect 22 0 19 0; +#X connect 22 1 32 0; +#X connect 22 2 21 0; +#X connect 22 3 30 1; +#X connect 23 0 24 0; +#X connect 24 0 18 0; +#X connect 25 0 18 1; +#X connect 27 0 25 0; +#X connect 28 0 29 0; +#X connect 29 0 27 0; +#X connect 30 0 31 0; +#X connect 31 0 18 0; +#X connect 31 1 18 2; +#X connect 32 0 20 0; +#X connect 32 1 33 0; +#X connect 33 0 34 0; +#X connect 34 0 30 0; +#X connect 38 0 47 0; +#X connect 40 0 38 0; +#X connect 41 0 42 0; +#X connect 42 0 40 0; +#X connect 43 0 44 0; +#X connect 45 0 40 0; +#X connect 46 0 0 1; +#X connect 46 1 0 2; +#X connect 46 2 0 3; +#X connect 47 0 39 0; +#X connect 47 1 48 0; +#X connect 48 1 50 0; +#X connect 49 0 51 0; +#X connect 50 1 49 1; +#X connect 50 2 49 3; +#X connect 52 0 45 0; +#X connect 53 0 40 0; +#X connect 54 0 10 0; +#X connect 54 1 53 1; +#X connect 55 0 46 0; +#X connect 60 0 1 0; +#X restore 347 236 pd orbit; +#X obj 35 210 tgl 20 1 empty empty start\ flocking\ animation 0 -10 0 12 #fcfcfc #000000 #000000 1 1; +#X text 23 18 create/destroy the GEM window; +#X obj 345 288 boids-params \$0; +#A saved flyrect -2 2 -2 2; +#A saved dimensions 3; +#A saved number 16; +#A saved neighbors 4; +#A saved maxspeed 12.99; +#A saved minspeed 2.42; +#A saved center 0.520001; +#A saved attract 0.860001; +#A saved match 0.420001; +#A saved avoid 1.3; +#A saved repel 0.670002; +#A saved edgedist 0.36; +#A saved speed 2.3; +#A saved inertia 0.78; +#A saved accel 0.640001; +#A saved prefdist 2.3; +#X obj 590 26 loadbang; +#X obj 590 51 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 590 76 s \$0-reset; +#X msg 73 348 reset; +#X obj 198 366 r \$0-boids-params; +#X msg 78 373 dump; +#X obj 103 459 print dump; +#X text 25 102 Change parameters to see their effect:; +#X floatatom 93 222 5 0 0 0 - - - 0; +#X obj 35 248 metro 25; +#X text 134 222 animation speed; +#X msg 52 313 attractpt \$1 \$2 \$3; +#X obj 347 172 tgl 20 1 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 1 1; +#X obj 52 287 r \$0-orbit-translation; +#X text 413 223 or click+drag for XY; +#X text 412 236 and middle-click to move Z; +#X text 339 133 ATTRACTION POINT, f 17; +#X obj 35 489 clone -x gemboid 16 \$0 1; +#X obj 226 279 loadbang; +#X obj 198 392 list trim; +#X floatatom 591 411 5 0 0 0 - - - 0; +#X obj 592 466 s \$0-size; +#X obj 591 438 / 100; +#X obj 593 497 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 593 522 s \$0-vis-bounds; +#N canvas 404 138 622 848 flock 0; +#X obj 96 29 inlet; +#X obj 96 54 route 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; +#X obj 96 79 unpack f f f; +#X obj 113 106 unpack f f f; +#X obj 143 136 unpack f f f; +#X obj 160 163 unpack f f f; +#X obj 191 192 unpack f f f; +#X obj 208 219 unpack f f f; +#X obj 238 249 unpack f f f; +#X obj 255 276 unpack f f f; +#X obj 291 312 unpack f f f; +#X obj 308 339 unpack f f f; +#X obj 338 369 unpack f f f; +#X obj 355 396 unpack f f f; +#X obj 386 425 unpack f f f; +#X obj 403 452 unpack f f f; +#X obj 428 479 unpack f f f; +#X obj 442 508 unpack f f f; +#X obj 38 279 +; +#X obj 38 304 +; +#X obj 38 329 +; +#X obj 38 354 +; +#X obj 39 381 +; +#X obj 39 406 +; +#X obj 39 431 +; +#X obj 39 456 +; +#X obj 38 483 +; +#X obj 38 508 +; +#X obj 38 533 +; +#X obj 38 558 +; +#X obj 39 585 +; +#X obj 39 610 +; +#X obj 39 635 +; +#X obj 78 279 +; +#X obj 78 304 +; +#X obj 78 329 +; +#X obj 78 354 +; +#X obj 79 381 +; +#X obj 79 406 +; +#X obj 79 431 +; +#X obj 79 456 +; +#X obj 78 483 +; +#X obj 78 508 +; +#X obj 78 533 +; +#X obj 78 558 +; +#X obj 79 585 +; +#X obj 79 610 +; +#X obj 79 635 +; +#X obj 112 283 +; +#X obj 112 308 +; +#X obj 112 333 +; +#X obj 112 358 +; +#X obj 113 385 +; +#X obj 113 410 +; +#X obj 113 435 +; +#X obj 113 460 +; +#X obj 112 487 +; +#X obj 112 512 +; +#X obj 112 537 +; +#X obj 112 562 +; +#X obj 113 589 +; +#X obj 113 614 +; +#X obj 113 639 +; +#X obj 39 660 / 16; +#X obj 84 668 / 16; +#X obj 128 670 / 16; +#X obj 49 723 pack f f f; +#X obj 48 755 s \$0-mass-center; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 1 1 3 0; +#X connect 1 2 4 0; +#X connect 1 3 5 0; +#X connect 1 4 6 0; +#X connect 1 5 7 0; +#X connect 1 6 8 0; +#X connect 1 7 9 0; +#X connect 1 8 10 0; +#X connect 1 9 11 0; +#X connect 1 10 12 0; +#X connect 1 11 13 0; +#X connect 1 12 14 0; +#X connect 1 13 15 0; +#X connect 1 14 16 0; +#X connect 1 15 17 0; +#X connect 2 0 18 0; +#X connect 2 1 33 0; +#X connect 2 2 48 0; +#X connect 3 0 18 1; +#X connect 3 1 33 1; +#X connect 3 2 48 1; +#X connect 4 0 19 1; +#X connect 4 1 34 1; +#X connect 4 2 49 1; +#X connect 5 0 20 1; +#X connect 5 1 35 1; +#X connect 5 2 50 1; +#X connect 6 0 21 1; +#X connect 6 1 36 1; +#X connect 6 2 51 1; +#X connect 7 0 22 1; +#X connect 7 1 37 1; +#X connect 7 2 52 1; +#X connect 8 0 23 1; +#X connect 8 1 38 1; +#X connect 8 2 53 1; +#X connect 9 0 24 1; +#X connect 9 1 39 1; +#X connect 9 2 54 1; +#X connect 10 0 25 1; +#X connect 10 1 40 1; +#X connect 10 2 55 1; +#X connect 11 0 26 1; +#X connect 11 1 41 1; +#X connect 11 2 56 1; +#X connect 12 0 27 1; +#X connect 12 1 42 1; +#X connect 12 2 57 1; +#X connect 13 0 28 1; +#X connect 13 1 43 1; +#X connect 13 2 58 1; +#X connect 14 0 29 1; +#X connect 14 1 44 1; +#X connect 14 2 59 1; +#X connect 15 0 30 1; +#X connect 15 1 45 1; +#X connect 15 2 60 1; +#X connect 16 0 31 1; +#X connect 16 1 46 1; +#X connect 16 2 61 1; +#X connect 17 0 32 1; +#X connect 17 1 47 1; +#X connect 17 2 62 1; +#X connect 18 0 19 0; +#X connect 19 0 20 0; +#X connect 20 0 21 0; +#X connect 21 0 22 0; +#X connect 22 0 23 0; +#X connect 23 0 24 0; +#X connect 24 0 25 0; +#X connect 25 0 26 0; +#X connect 26 0 27 0; +#X connect 27 0 28 0; +#X connect 28 0 29 0; +#X connect 29 0 30 0; +#X connect 30 0 31 0; +#X connect 31 0 32 0; +#X connect 32 0 63 0; +#X connect 33 0 34 0; +#X connect 34 0 35 0; +#X connect 35 0 36 0; +#X connect 36 0 37 0; +#X connect 37 0 38 0; +#X connect 38 0 39 0; +#X connect 39 0 40 0; +#X connect 40 0 41 0; +#X connect 41 0 42 0; +#X connect 42 0 43 0; +#X connect 43 0 44 0; +#X connect 44 0 45 0; +#X connect 45 0 46 0; +#X connect 46 0 47 0; +#X connect 47 0 64 0; +#X connect 48 0 49 0; +#X connect 49 0 50 0; +#X connect 50 0 51 0; +#X connect 51 0 52 0; +#X connect 52 0 53 0; +#X connect 53 0 54 0; +#X connect 54 0 55 0; +#X connect 55 0 56 0; +#X connect 56 0 57 0; +#X connect 57 0 58 0; +#X connect 58 0 59 0; +#X connect 59 0 60 0; +#X connect 60 0 61 0; +#X connect 61 0 62 0; +#X connect 62 0 65 0; +#X connect 63 0 66 0; +#X connect 64 0 66 1; +#X connect 65 0 66 2; +#X connect 66 0 67 0; +#X restore 35 514 pd flock; +#X text 371 172 move around (like a pray); +#X msg 225 305 mode 2; +#X obj 35 433 boids; +#X obj 300 20 declare -lib Gem -lib boids -path boids; +#X connect 0 0 1 0; +#X connect 1 0 0 0; +#X connect 3 0 15 0; +#X connect 6 0 7 0; +#X connect 7 0 8 0; +#X connect 9 0 34 0; +#X connect 10 0 25 0; +#X connect 11 0 34 0; +#X connect 14 0 15 1; +#X connect 15 0 34 0; +#X connect 17 0 34 0; +#X connect 18 0 2 0; +#X connect 19 0 17 0; +#X connect 23 0 31 0; +#X connect 24 0 33 0; +#X connect 25 0 34 0; +#X connect 26 0 28 0; +#X connect 28 0 27 0; +#X connect 29 0 30 0; +#X connect 33 0 34 0; +#X connect 34 0 23 0; +#X connect 34 1 12 0; diff --git a/examples/boids-with-gemlist.pd b/examples/boids-gemlist.pd similarity index 52% rename from examples/boids-with-gemlist.pd rename to examples/boids-gemlist.pd index ebc993f..e5cd757 100644 --- a/examples/boids-with-gemlist.pd +++ b/examples/boids-gemlist.pd @@ -1,39 +1,37 @@ -#N canvas 521 28 520 660 10; -#X declare -path boids -lib Gem; +#N canvas 1018 93 597 774 10; +#X declare -path boids -lib Gem -lib boids; #X msg 432 52 create; -#N canvas 494 140 629 324 gemwin 0; -#X obj 219 190 gemwin; +#N canvas 1028 103 629 324 gemwin 0; +#X obj 170 199 gemwin; #X obj 66 194 outlet; #X obj 67 10 inlet; #X obj 67 41 route create; #X msg 67 70 set destroy; #X msg 157 70 set create; -#X msg 350 115 destroy \, reset; -#X msg 238 71 color 0 0 0.5; -#X msg 212 146 create \, 1 \, frame 30 \, color 1 1 1; +#X msg 160 114 destroy \, reset; #X obj 157 39 loadbang; +#X obj 359 38 gemhead; +#X obj 359 61 world_light; +#X msg 138 145 reset \, create \, lighting 1 \, fogmode 1 \, fog 0.04 \, fogcolor 0.07 0.41 0.74 \, 1 \, frame 30 \, color 0 0 0.1 0; #X connect 2 0 3 0; #X connect 3 0 4 0; -#X connect 3 0 8 0; +#X connect 3 0 10 0; #X connect 3 1 5 0; #X connect 3 1 6 0; #X connect 4 0 1 0; #X connect 5 0 1 0; #X connect 6 0 0 0; -#X connect 7 0 0 0; -#X connect 8 0 0 0; -#X connect 9 0 5 0; +#X connect 7 0 5 0; +#X connect 8 0 9 0; +#X connect 10 0 0 0; #X restore 432 72 pd gemwin; #X text 27 61 There is more information about the technique used in this patch in the Gem documentation \, mainly at the end of the 02.advanced section.; #X text 29 32 manage lots of boids using [gemlist]; -#X floatatom 314 241 5 0 0 0 - - - 0; -#X floatatom 359 241 5 0 0 0 - - - 0; #N canvas 0 22 466 396 orbit 0; #X floatatom 103 160 5 0 0 0 - - - 0; #X obj 103 187 expr $f1 * (3.141593/180.); #X obj 103 45 inlet; -#X obj 166 314 outlet; -#X obj 103 314 outlet; +#X obj 107 342 outlet; #N canvas 0 0 450 300 pol2cart 0; #X obj 79 42 inlet r; #X obj 159 42 inlet phi; @@ -62,78 +60,40 @@ #X connect 11 0 10 0; #X restore 103 254 pd pol2cart; #X msg 103 210 1.5 \$1; -#X obj 103 277 swap, f 11; +#X obj 103 277 swap, f 5; #X obj 103 68 i; #X obj 103 91 + 1; #X obj 103 114 % 360; #X obj 103 137 t f f; +#X obj 196 259 sin; +#X obj 107 314 pack f f f; +#X obj 180 287 * 3; +#X obj 196 236 * 0.5; #X connect 0 0 1 0; -#X connect 1 0 6 0; -#X connect 2 0 8 0; -#X connect 5 0 7 0; -#X connect 5 1 7 1; -#X connect 6 0 5 0; -#X connect 7 0 4 0; -#X connect 7 1 3 0; +#X connect 1 0 5 0; +#X connect 1 0 14 0; +#X connect 2 0 7 0; +#X connect 4 0 6 0; +#X connect 4 1 6 1; +#X connect 5 0 4 0; +#X connect 6 0 12 0; +#X connect 6 1 12 1; +#X connect 7 0 8 0; #X connect 8 0 9 0; #X connect 9 0 10 0; -#X connect 10 0 11 0; -#X connect 11 0 0 0; -#X connect 11 1 8 1; +#X connect 10 0 0 0; +#X connect 10 1 7 1; +#X connect 11 0 13 0; +#X connect 12 0 3 0; +#X connect 13 0 12 2; +#X connect 14 0 11 0; #X restore 314 219 pd orbit; -#X obj 314 188 spigot; -#X obj 350 167 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 0 1; -#X msg 128 313 attractpt \$1 \$2; -#X obj 314 264 pack 0 0; +#X obj 359 154 tgl 15 0 empty empty empty 0 -6 0 8 #fcfcfc #000000 #000000 0 1; #X obj 47 133 gemhead; #X obj 47 590 translateXYZ; #X obj 47 509 alpha; -#X obj 47 616 circle 0.05; #X obj 47 394 gemlist; #X obj 47 420 separator; -#N canvas 754 114 494 546 init 0; -#X obj 34 20 inlet; -#X msg 198 102 neighbors 4; -#X msg 203 389 speed 3; -#X msg 203 479 prefdist 1.5; -#X msg 203 149 maxspeed 1.5; -#X msg 203 179 minspeed 1.2; -#X msg 203 209 center 1.2; -#X msg 203 239 attract 1.25; -#X msg 203 269 match 0.3; -#X msg 203 329 repel 3.5; -#X msg 203 299 avoid 3.5; -#X msg 203 359 edgedist 3; -#X msg 203 420 inertia 4.5; -#X msg 203 449 accel 2.5; -#X obj 34 520 outlet; -#X connect 0 0 1 0; -#X connect 0 0 2 0; -#X connect 0 0 3 0; -#X connect 0 0 4 0; -#X connect 0 0 5 0; -#X connect 0 0 6 0; -#X connect 0 0 7 0; -#X connect 0 0 8 0; -#X connect 0 0 9 0; -#X connect 0 0 10 0; -#X connect 0 0 11 0; -#X connect 0 0 12 0; -#X connect 0 0 13 0; -#X connect 1 0 14 0; -#X connect 2 0 14 0; -#X connect 3 0 14 0; -#X connect 4 0 14 0; -#X connect 5 0 14 0; -#X connect 6 0 14 0; -#X connect 7 0 14 0; -#X connect 8 0 14 0; -#X connect 9 0 14 0; -#X connect 10 0 14 0; -#X connect 11 0 14 0; -#X connect 12 0 14 0; -#X connect 13 0 14 0; -#X restore 60 220 pd init; #N canvas 0 22 418 379 circle 0; #X obj 101 37 gemhead; #X obj 99 201 translateXYZ; @@ -154,7 +114,7 @@ #X connect 5 0 4 0; #X connect 6 0 1 0; #X connect 7 0 6 0; -#X restore 314 299 pd circle to follow; +#X restore 337 287 pd circle to follow; #X obj 47 158 trigger bang anything bang; #N canvas 1 98 474 324 random 0; #X obj 47 130 random 1000; @@ -191,45 +151,78 @@ #X restore 200 394 pd random color lists; #X obj 47 368 trigger bang anything bang; #X obj 200 449 unpack 0 0 0; -#X obj 77 548 unpack 0 0 0; -#X obj 47 342 boids2d 100; #X obj 47 459 color; -#X obj 265 6 declare -path boids -lib Gem; -#X obj 323 93 loadbang; -#X msg 323 115 1; -#X obj 323 137 t b f; +#X obj 47 342 boids 100; +#X obj 125 508 list split 1; +#X obj 75 565 unpack f f f; +#X obj 158 531 list split 3; +#X msg 74 309 attractpt \$1 \$2 \$3; +#X obj 310 262 t a a; +#X listbox 321 239 30 0 0 0 - - - 0; +#X obj 309 458 boids-params \$0; +#A saved flyrect -3 3 -3 3; +#A saved dimensions 3; +#A saved number 1000; +#A saved neighbors 7; +#A saved maxspeed 1.5; +#A saved minspeed 1.2; +#A saved center 0.8; +#A saved attract 0.97; +#A saved match 0.93; +#A saved avoid 0.920002; +#A saved repel 5.23; +#A saved edgedist 2.48; +#A saved speed 3; +#A saved inertia 0.970001; +#A saved accel 0.740001; +#A saved prefdist 52.49; +#X obj 60 220 r \$0-boids-params; +#X obj 53 246 list trim; +#X obj 314 188 spigot 1; +#X obj 50 711 sphere 0.05 3; +#X obj 48 667 rotateXYZ; +#X obj 182 216 loadbang; +#X msg 182 239 mode 2; +#X obj 194 570 list split 3; +#X obj 130 622 unpack f f f; +#X obj 265 6 declare -path boids -lib Gem -lib boids; #X connect 0 0 1 0; #X connect 1 0 0 0; -#X connect 4 0 10 0; -#X connect 5 0 10 1; -#X connect 6 0 4 0; -#X connect 6 1 5 0; -#X connect 7 0 6 0; -#X connect 8 0 7 1; -#X connect 9 0 24 0; -#X connect 10 0 9 0; -#X connect 10 0 18 0; -#X connect 11 0 19 0; -#X connect 12 0 14 0; -#X connect 13 0 12 0; -#X connect 15 0 16 0; -#X connect 16 0 25 0; -#X connect 17 0 24 0; -#X connect 19 0 24 0; -#X connect 19 1 15 1; -#X connect 19 2 7 0; -#X connect 19 2 20 1; -#X connect 20 0 22 0; -#X connect 20 0 25 1; -#X connect 21 0 15 0; -#X connect 21 1 23 0; -#X connect 21 2 20 0; -#X connect 22 0 13 1; -#X connect 23 1 12 1; -#X connect 23 2 12 2; -#X connect 24 0 21 0; -#X connect 25 0 13 0; -#X connect 27 0 28 0; -#X connect 28 0 29 0; -#X connect 29 0 17 0; -#X connect 29 1 8 0; +#X connect 4 0 22 0; +#X connect 4 0 23 0; +#X connect 5 0 27 1; +#X connect 6 0 12 0; +#X connect 7 0 29 0; +#X connect 8 0 7 0; +#X connect 9 0 10 0; +#X connect 10 0 16 0; +#X connect 12 0 17 0; +#X connect 12 1 9 1; +#X connect 12 2 13 1; +#X connect 12 2 27 0; +#X connect 13 0 15 0; +#X connect 13 0 16 1; +#X connect 14 0 9 0; +#X connect 14 1 18 0; +#X connect 14 2 13 0; +#X connect 15 0 8 1; +#X connect 16 0 8 0; +#X connect 17 0 14 0; +#X connect 18 1 20 0; +#X connect 19 0 7 1; +#X connect 19 1 7 2; +#X connect 19 2 7 3; +#X connect 20 0 19 0; +#X connect 20 1 32 0; +#X connect 21 0 17 0; +#X connect 22 0 21 0; +#X connect 22 1 11 0; +#X connect 25 0 26 0; +#X connect 26 0 17 0; +#X connect 27 0 4 0; +#X connect 29 0 28 0; +#X connect 30 0 31 0; +#X connect 31 0 17 0; +#X connect 32 1 33 0; +#X connect 33 1 29 1; +#X connect 33 2 29 3; diff --git a/examples/boids-struct.pd b/examples/boids-struct.pd new file mode 100644 index 0000000..7a0f129 --- /dev/null +++ b/examples/boids-struct.pd @@ -0,0 +1,282 @@ +#N canvas 986 25 614 803 12; +#X declare -lib boids -path boids; +#N struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2; +#N struct \$0-attractpoint float x float y; +#N canvas 0 25 554 469 \$0-data 0; +#X scalar \$0-template 742 742 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 927 927 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 726 726 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 918 918 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 628 628 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 565 565 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 485 485 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 304 304 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 55 55 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 300 300 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 157 157 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 737 737 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 433 433 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 271 271 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 987 987 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-template 916 916 0 -6 0 0 -18 6 0 \;; +#X scalar \$0-attractpoint 0 0 \;; +#X coords -300 -300 300 300 300 300 2 100 100; +#X restore 24 69 pd \$0-data; +#N canvas 125 78 524 337 \$0-template 0; +#X text 59 231 Struct that defines each boid diamond; +#X text 91 270 color can be changed with k; +#X msg 360 225 clear; +#X obj 360 250 s pd-\$0-data; +#X obj 41 95 filledpolygon k1 k2 k3 x0 y0 x1 y1 x2 y2; +#X obj 40 20 struct \$0-template float k1 float k2 float k3 float x0 float y0 float x1 float y1 float x2 float y2; +#X connect 2 0 3 0; +#X restore 340 364 pd \$0-template; +#N canvas 1059 309 598 557 \$0-attractpoint 0; +#X obj 232 239 f \$0; +#X msg 232 264 traverse pd-\$1-data \, bang; +#X obj 232 289 pointer; +#X obj 90 138 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X msg 443 234 clear; +#X obj 443 259 s pd-\$0-data; +#X obj 56 109 loadbang; +#X obj 63 165 t b b b b b, f 34; +#X obj 86 392 r \$0-attractpt; +#X obj 42 28 struct \$0-attractpoint float x float y; +#X obj 56 481 s \$0-init-boids; +#X obj 89 415 set \$0-attractpoint x y; +#X obj 124 324 append \$0-attractpoint x y; +#X msg 124 296 0 0; +#X obj 39 68 drawcurve 0 1 0 0 0 10 10 10 10 0 0 0; +#X obj 130 108 r \$0-init; +#X text 267 116 Struct that defines the attraction circle; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 2 0 12 2; +#X connect 3 0 7 0; +#X connect 4 0 5 0; +#X connect 6 0 7 0; +#X connect 7 0 10 0; +#X connect 7 1 13 0; +#X connect 7 2 0 0; +#X connect 7 4 4 0; +#X connect 8 0 11 0; +#X connect 12 0 11 2; +#X connect 13 0 12 0; +#X connect 15 0 7 0; +#X restore 341 341 pd \$0-attractpoint; +#X obj 325 436 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 325 497 metro 10; +#X obj 326 711 clone struct-boid 16 \$0; +#X msg 348 564 reset; +#X obj 469 583 r \$0-boids-params; +#X obj 385 665 print; +#X msg 341 537 dump; +#X msg 485 546 attractpt \$1 \$2; +#X obj 499 372 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X obj 499 397 s \$0-init; +#X text 48 411 ATTRACTION POINT; +#X text 354 430 Update boids; +#X floatatom 357 467 5 0 0 0 - - - 0; +#X text 33 18 A 2d boids example using data structures; +#X obj 408 545 loadbang; +#X obj 325 632 boids 16; +#X obj 470 606 list trim; +#X floatatom 113 557 6 0 0 0 xpos - - 0; +#X floatatom 202 560 5 0 0 0 ypos - - 0; +#X obj 117 597 / 100; +#X obj 195 595 / 100; +#X msg 413 572 mode 2; +#X obj 339 58 boids-params \$0; +#A saved flyrect -300 300 -300 300; +#A saved dimensions 2; +#A saved number 16; +#A saved neighbors 4; +#A saved attract 0.25; +#A saved center 0.02; +#A saved match 0.0500007; +#A saved avoid 0.919994; +#A saved prefdist 55; +#A saved speed 42; +#A saved minspeed 4; +#A saved maxspeed 46; +#A saved inertia 0.47; +#A saved accel 0.230001; +#A saved edgedist 15; +#A saved repel 0.410001; +#X obj 58 443 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 61 489 metro 50; +#X floatatom 132 479 5 0 0 0 - - - 0; +#N canvas 0 0 450 300 atract-point 0; +#N canvas 323 118 689 551 random-walk 0; +#X obj 167 125 f; +#X obj 74 197 random 2; +#X obj 167 150 t b b f; +#X obj 195 351 +; +#X obj 140 276 + 1; +#X obj 122 332 *; +#X msg 64 305 -1; +#X obj 278 85 moses 0; +#X obj 324 115 moses 100; +#X obj 278 115 * -1; +#X obj 384 143 * -1; +#X obj 384 168 + 200; +#X msg 97 305 1; +#X text 80 223 sign; +#X text 153 180 magnitude; +#X text 228 340 add prev value; +#X text 227 355 to random increment; +#X obj 304 202 t f f; +#X obj 362 284 outlet; +#X obj 167 24 inlet; +#X obj 163 66 b; +#X text 97 461 Pure Data/2.control.examples/22.random-walk.pd, f 74; +#X text 140 439 open the browser and look for:; +#X obj 349 243 * 0.01; +#X obj 74 276 sel; +#X obj 140 200 random 10; +#X obj 203 241 b; +#X obj 203 266 random 30; +#X obj 140 238 moses 8; +#X connect 0 0 2 0; +#X connect 1 0 24 0; +#X connect 2 0 1 0; +#X connect 2 1 25 0; +#X connect 2 2 3 1; +#X connect 3 0 7 0; +#X connect 4 0 5 1; +#X connect 5 0 3 0; +#X connect 6 0 5 0; +#X connect 7 0 9 0; +#X connect 7 1 8 0; +#X connect 8 0 17 0; +#X connect 8 1 10 0; +#X connect 9 0 17 0; +#X connect 10 0 11 0; +#X connect 11 0 17 0; +#X connect 12 0 5 0; +#X connect 17 0 0 1; +#X connect 17 1 23 0; +#X connect 19 0 20 0; +#X connect 20 0 0 0; +#X connect 23 0 18 0; +#X connect 24 0 6 0; +#X connect 24 1 12 0; +#X connect 25 0 28 0; +#X connect 26 0 27 0; +#X connect 27 0 4 0; +#X connect 28 0 4 0; +#X connect 28 1 26 0; +#X restore 90 121 pd random-walk; +#X obj 88 163 * 600; +#X obj 88 188 - 300; +#N canvas 657 108 689 551 random-walk 0; +#X obj 167 125 f; +#X obj 74 197 random 2; +#X obj 167 150 t b b f; +#X obj 195 351 +; +#X obj 140 276 + 1; +#X obj 122 332 *; +#X msg 64 305 -1; +#X obj 278 85 moses 0; +#X obj 324 115 moses 100; +#X obj 278 115 * -1; +#X obj 384 143 * -1; +#X obj 384 168 + 200; +#X msg 97 305 1; +#X text 80 223 sign; +#X text 145 221 magnitude; +#X text 228 340 add prev value; +#X text 227 355 to random increment; +#X obj 304 202 t f f; +#X obj 362 284 outlet; +#X obj 167 24 inlet; +#X obj 163 66 b; +#X text 97 461 Pure Data/2.control.examples/22.random-walk.pd, f 74; +#X text 140 439 open the browser and look for:; +#X obj 349 243 * 0.01; +#X obj 74 276 sel; +#X obj 140 198 random 10; +#X obj 203 241 b; +#X obj 203 266 random 30; +#X obj 140 238 moses 8; +#X connect 0 0 2 0; +#X connect 1 0 24 0; +#X connect 2 0 1 0; +#X connect 2 1 25 0; +#X connect 2 2 3 1; +#X connect 3 0 7 0; +#X connect 4 0 5 1; +#X connect 5 0 3 0; +#X connect 6 0 5 0; +#X connect 7 0 9 0; +#X connect 7 1 8 0; +#X connect 8 0 17 0; +#X connect 8 1 10 0; +#X connect 9 0 17 0; +#X connect 10 0 11 0; +#X connect 11 0 17 0; +#X connect 12 0 5 0; +#X connect 17 0 0 1; +#X connect 17 1 23 0; +#X connect 19 0 20 0; +#X connect 20 0 0 0; +#X connect 23 0 18 0; +#X connect 24 0 6 0; +#X connect 24 1 12 0; +#X connect 25 0 28 0; +#X connect 26 0 27 0; +#X connect 27 0 4 0; +#X connect 28 0 4 0; +#X connect 28 1 26 0; +#X restore 134 145 pd random-walk; +#X obj 132 187 * 600; +#X obj 132 212 - 300; +#X obj 84 95 t b b; +#X obj 88 213 pack; +#X obj 85 246 s \$0-attractpt; +#X obj 59 10 inlet; +#X obj 206 15 inlet; +#X obj 268 19 inlet; +#X obj 243 72 t b f; +#X obj 207 65 f; +#X connect 0 0 1 0; +#X connect 1 0 2 0; +#X connect 2 0 7 0; +#X connect 3 0 4 0; +#X connect 4 0 5 0; +#X connect 5 0 7 1; +#X connect 6 0 0 0; +#X connect 6 1 3 0; +#X connect 7 0 8 0; +#X connect 9 0 6 0; +#X connect 10 0 13 0; +#X connect 11 0 12 0; +#X connect 12 0 13 0; +#X connect 12 1 4 0; +#X connect 13 0 1 0; +#X restore 65 629 pd atract-point; +#X text 79 443 random walk; +#X obj 486 518 r \$0-attractpt; +#X text 80 518 manual input (turn random off first), f 18; +#X obj 360 21 declare -lib boids -path boids; +#X connect 3 0 4 0; +#X connect 4 0 18 0; +#X connect 6 0 18 0; +#X connect 7 0 19 0; +#X connect 9 0 18 0; +#X connect 10 0 18 0; +#X connect 11 0 12 0; +#X connect 15 0 4 1; +#X connect 17 0 24 0; +#X connect 18 0 5 0; +#X connect 18 1 8 0; +#X connect 19 0 18 0; +#X connect 20 0 22 0; +#X connect 21 0 23 0; +#X connect 22 0 29 1; +#X connect 23 0 29 2; +#X connect 24 0 18 0; +#X connect 26 0 27 0; +#X connect 27 0 29 0; +#X connect 28 0 27 1; +#X connect 31 0 10 0; diff --git a/examples/gemboid.pd b/examples/gemboid.pd deleted file mode 100644 index 248dbaa..0000000 --- a/examples/gemboid.pd +++ /dev/null @@ -1,46 +0,0 @@ -#N canvas 0 0 450 300 12; -#X obj 61 64 gemhead; -#X obj 61 241 translateXYZ; -#X obj 152 202 unpack 0 0 0; -#X obj 152 41 inlet; -#X obj 61 195 alpha; -#X obj 61 125 color 1 0.5 0 0.5; -#N canvas 0 22 474 324 rand_color 0; -#X obj 47 130 random 1000; -#X obj 47 171 * 0.001; -#X obj 131 130 random 1000; -#X obj 131 171 * 0.001; -#X obj 214 131 random 1000; -#X obj 214 172 * 0.001; -#X obj 47 83 t b b b; -#X obj 47 256 outlet; -#X obj 47 217 pack 0 0 0 0.5; -#X obj 47 26 r \$1-init; -#X connect 0 0 1 0; -#X connect 1 0 8 0; -#X connect 2 0 3 0; -#X connect 3 0 8 1; -#X connect 4 0 5 0; -#X connect 5 0 8 2; -#X connect 6 0 0 0; -#X connect 6 1 2 0; -#X connect 6 2 4 0; -#X connect 8 0 7 0; -#X connect 9 0 6 0; -#X restore 177 68 pd rand_color; -#X obj 61 268 circle 0.05; -#X obj 177 91 t a a; -#X msg 209 120 1; -#X text 34 14 helper abstraction for boids examples with Gem; -#X connect 0 0 5 0; -#X connect 1 0 7 0; -#X connect 2 0 1 1; -#X connect 2 1 1 2; -#X connect 2 2 1 3; -#X connect 3 0 2 0; -#X connect 4 0 1 0; -#X connect 5 0 4 0; -#X connect 6 0 8 0; -#X connect 8 0 5 1; -#X connect 8 1 9 0; -#X connect 9 0 4 1; diff --git a/help/boids-help.pd b/help/boids-help.pd new file mode 100644 index 0000000..43ac55b --- /dev/null +++ b/help/boids-help.pd @@ -0,0 +1,201 @@ +#N canvas 506 25 822 888 12; +#X declare -path boids; +#X floatatom 492 656 5 0 0 0 - - - 0; +#X floatatom 536 654 5 0 0 0 - - - 0; +#X msg 80 386 mode \$1; +#X text 145 424 reset boids randomly inside flyrect; +#X text 34 827 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); +#X text 25 73 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; +#X text 25 109 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; +#X text 27 759 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; +#X text 37 805 arguments: number of boids \, output mode; +#X obj 78 536 print dump; +#X obj 19 10 cnv 15 800 48 empty empty boids 15 20 2 24 #dce0c8 #404040 0; +#X text 35 850 float/2d/3d adaptation 08/2005 by a. sier / jasch; +#N canvas 88 105 494 344 META 0; +#X text 13 182 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; +#X text 13 160 AUTHOR Eric L. Singer; +#X text 13 6 KEYWORDS control; +#X text 13 50 DESCRIPTION bird flight and animal flock simulator; +#X text 13 72 INLET_0 bang dump mode reset number neighbors maxspeed minspeed center attract match avoid repel edgedist speed inertia accel prefdist flyrect attractpt; +#X text 13 116 OUTLET_0 list; +#X text 13 138 OUTLET_1 list; +#X text 13 28 LICENSE GPL v2; +#X restore 760 21 pd META; +#X obj 518 751 s \$0-boids-params; +#X text 225 654 ..., f 4; +#X floatatom 24 677 5 0 0 0 - - - 0; +#X floatatom 62 695 5 0 0 0 - - - 0; +#X floatatom 127 675 5 0 0 0 - - - 0; +#X floatatom 164 694 5 0 0 0 - - - 0; +#X obj 79 360 hradio 18 1 0 4 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X msg 53 316 dump; +#X msg 99 422 reset; +#X obj 32 228 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; +#N canvas 72 225 794 467 output-mode 0; +#X floatatom 156 318 5 0 0 0 - - - 0; +#X floatatom 186 344 5 0 0 0 - - - 0; +#X floatatom 219 367 5 0 0 0 - - - 0; +#X floatatom 252 325 5 0 0 0 - - - 0; +#X floatatom 343 254 5 0 0 0 - - - 0; +#X floatatom 373 279 5 0 0 0 - - - 0; +#X floatatom 390 302 5 0 0 0 - - - 0; +#X floatatom 457 297 5 0 0 0 - - - 0; +#X floatatom 468 321 5 0 0 0 - - - 0; +#X floatatom 492 351 5 0 0 0 - - - 0; +#X obj 252 63 list length; +#X obj 183 112 list prepend; +#X obj 186 66 t a a; +#X floatatom 49 228 5 0 0 0 - - - 0; +#X floatatom 86 247 5 0 0 0 - - - 0; +#X text 371 400 (2) new and old with delta positions; +#X text 141 407 (1) new and old positions; +#X text 39 267 (0) new position only; +#X obj 186 17 inlet; +#X text 298 14 this patch shows the different output modes of the boids external.; +#X text 391 45 output mode:; +#X text 426 99 (1) new and old positions; +#X text 426 77 (0) new position only; +#X obj 47 203 unpack f f f; +#X floatatom 129 228 5 0 0 0 - - - 0; +#X obj 198 262 unpack f f f f f f; +#X floatatom 274 354 5 0 0 0 - - - 0; +#X floatatom 300 380 5 0 0 0 - - - 0; +#X floatatom 552 307 5 0 0 0 - - - 0; +#X floatatom 563 331 5 0 0 0 - - - 0; +#X floatatom 587 361 5 0 0 0 - - - 0; +#X obj 343 229 unpack f f f f f f f f f, f 33; +#X obj 189 141 route 3 6 9; +#X text 428 121 (2) new and old with speed \, azim \, elev; +#X text 428 145 (3) position and direction vectors; +#X text 138 424 (3) position and direction vectors; +#X connect 10 0 11 1; +#X connect 11 0 32 0; +#X connect 12 0 11 0; +#X connect 12 1 10 0; +#X connect 18 0 12 0; +#X connect 23 0 13 0; +#X connect 23 1 14 0; +#X connect 23 2 24 0; +#X connect 25 0 0 0; +#X connect 25 1 1 0; +#X connect 25 2 2 0; +#X connect 25 3 3 0; +#X connect 25 4 26 0; +#X connect 25 5 27 0; +#X connect 31 0 4 0; +#X connect 31 1 5 0; +#X connect 31 2 6 0; +#X connect 31 3 7 0; +#X connect 31 4 8 0; +#X connect 31 5 9 0; +#X connect 31 6 28 0; +#X connect 31 7 29 0; +#X connect 31 8 30 0; +#X connect 32 0 23 0; +#X connect 32 1 25 0; +#X connect 32 2 31 0; +#X restore 251 605 pd output-mode; +#X floatatom 279 690 5 0 0 0 - - - 0; +#X floatatom 317 708 5 0 0 0 - - - 0; +#X obj 32 572 route 0 1 2 3 4 10 15, f 27; +#X text 164 363 see [pd-output-mode]; +#X obj 110 447 r \$0-boids-params; +#X obj 534 676 t b f; +#X text 98 308 Use the 'dump' message to output a list of the current parameter settings., f 42; +#X text 131 261 The flight parameters can be changed with messages -->, f 55; +#X text 488 571 ATTRACTION POINT; +#X text 487 592 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; +#X text 98 492 optional arguments: integer number of boids (default is 16); +#X text 165 508 next optional argument is mode (default is 0); +#X obj 32 175 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 24 651 unpack f f f; +#X obj 127 650 unpack f f f; +#X obj 279 664 unpack f f f; +#X floatatom 102 703 5 0 0 0 - - - 0; +#X floatatom 209 701 5 0 0 0 - - - 0; +#X floatatom 373 692 5 0 0 0 - - - 0; +#X msg 521 726 attractpt \$1 \$2 \$3; +#X text 632 660 point to which boids are attracted (x/y/z), f 21; +#X floatatom 588 656 5 0 0 0 - - - 0; +#X obj 586 678 t b f; +#X obj 522 700 pack f f f; +#X text 101 174 Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the X \, Y \, Z coordiantes for each boid., f 49; +#X obj 32 493 boids; +#X obj 32 200 metro 40; +#X obj 264 549 list length; +#X floatatom 264 574 5 0 0 0 - - - 0; +#X obj 533 121 boids-params \$0; +#A saved flyrect -1 1 -1 1; +#A saved dimensions 2; +#A saved number 16; +#A saved neighbors 4; +#A saved maxspeed 1.5; +#A saved minspeed 1.2; +#A saved center 1.2; +#A saved attract 1.25; +#A saved match 0.3; +#A saved avoid 3.5; +#A saved repel 3.5; +#A saved edgedist 3; +#A saved speed 3; +#A saved inertia 4.5; +#A saved accel 2.5; +#A saved prefdist 1.5; +#X obj 551 79 declare -path boids; +#X obj 565 841 boids2d; +#X obj 641 841 boids3d; +#X text 493 807 Aliases for previous versions:; +#N canvas 0 0 596 342 multidimensionality 0; +#X obj 37 137 boids; +#X msg 97 71 dimensions 5; +#X obj 34 24 bng 20 250 50 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000; +#X listbox 35 192 45 0 0 0 - - - 0; +#X text 316 129 NOTE: output mode 2 will not work; +#X obj 37 162 route 0 3; +#X listbox 55 227 45 0 0 0 - - - 0; +#X msg 117 99 attractpt 0.1 0.2 0.3 0.4 0.4; +#X text 171 28 Multidimensionality can be used; +#X connect 0 0 5 0; +#X connect 1 0 0 0; +#X connect 2 0 0 0; +#X connect 5 0 3 0; +#X connect 5 1 6 0; +#X connect 7 0 0 0; +#X restore 544 431 pd multidimensionality; +#X obj 109 468 list trim; +#X connect 0 0 47 0; +#X connect 1 0 29 0; +#X connect 2 0 49 0; +#X connect 19 0 2 0; +#X connect 20 0 49 0; +#X connect 21 0 49 0; +#X connect 22 0 49 0; +#X connect 26 0 37 0; +#X connect 26 1 38 0; +#X connect 26 5 39 0; +#X connect 26 6 23 0; +#X connect 26 6 51 0; +#X connect 28 0 59 0; +#X connect 29 0 47 0; +#X connect 29 1 47 1; +#X connect 36 0 50 0; +#X connect 37 0 15 0; +#X connect 37 1 16 0; +#X connect 37 2 40 0; +#X connect 38 0 17 0; +#X connect 38 1 18 0; +#X connect 38 2 41 0; +#X connect 39 0 24 0; +#X connect 39 1 25 0; +#X connect 39 2 42 0; +#X connect 43 0 13 0; +#X connect 45 0 46 0; +#X connect 46 0 47 0; +#X connect 46 1 47 2; +#X connect 47 0 43 0; +#X connect 49 0 26 0; +#X connect 49 1 9 0; +#X connect 50 0 22 0; +#X connect 51 0 52 0; +#X connect 59 0 49 0; diff --git a/help/boids-params-help.pd b/help/boids-params-help.pd new file mode 100644 index 0000000..ff27bb4 --- /dev/null +++ b/help/boids-params-help.pd @@ -0,0 +1,40 @@ +#N canvas 747 25 677 686 12; +#X text 263 38 Boids Parameters; +#X obj 82 259 boids-params \$0; +#A saved number 16; +#A saved neighbors 4; +#A saved maxspeed 1.47; +#A saved minspeed 1.2; +#A saved center 1.21; +#A saved attract 1.25; +#A saved match 0.3; +#A saved avoid 3.32; +#A saved repel 3.5; +#A saved edgedist 3.03; +#A saved speed 0.560001; +#A saved inertia 4.5; +#A saved accel 2.5; +#A saved prefdist 1.5; +#X text 331 296 <-- right-click open to se more info; +#X text 78 81 All available 14 parameters can be set using this abstraction. The parameters are stored after saving the main patch and can be reset to default with the "defaults" bang.; +#X obj 356 369 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 356 454 boids; +#X obj 388 488 print dump; +#X obj 356 522 route 0; +#X listbox 356 547 20 0 0 0 - - - 0; +#X obj 356 401 metro 10; +#X obj 445 371 r \$0-boids-params; +#X obj 445 398 list trim; +#X listbox 82 536 20 0 0 0 - - - 0; +#X text 78 143 To use the parameters \, connect and trim the list outlet to the [boids] object or receive with a trimmed [r \$0-boids-params].; +#X text 79 201 Note the \$0 as first argument \, which is simply a number to identify this unique set of parameters.; +#X text 78 599 To write or read parameters from disk \, send \$1-parameters the usual "write" or "read" you would send to [text]; +#X connect 1 0 12 0; +#X connect 4 0 9 0; +#X connect 5 0 7 0; +#X connect 5 1 6 0; +#X connect 7 0 8 0; +#X connect 9 0 5 0; +#X connect 10 0 11 0; +#X connect 11 0 5 0; +#X coords 0 686 1 685 230 270 0; diff --git a/help/boids2d-help.pd b/help/boids2d-help.pd new file mode 100644 index 0000000..1a40112 --- /dev/null +++ b/help/boids2d-help.pd @@ -0,0 +1,158 @@ +#N canvas 587 25 829 908 12; +#X declare -lib boids -path boids; +#X floatatom 506 694 5 0 0 0 - - - 0; +#X floatatom 550 692 5 0 0 0 - - - 0; +#X msg 80 386 mode \$1; +#X text 145 424 reset boids randomly inside flyrect; +#X text 40 814 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); +#X text 25 73 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; +#X text 25 109 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; +#X text 38 744 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; +#X text 43 792 arguments: number of boids \, output mode; +#X obj 78 536 print dump; +#X obj 19 10 cnv 15 800 48 empty empty boids2d 15 20 2 24 #dce0c8 #404040 0; +#X text 41 837 float/2d/3d adaptation 08/2005 by a. sier / jasch; +#X msg 535 764 attractpt \$1 \$2; +#X text 605 696 point to which boids are attracted (x/y), f 21; +#N canvas 88 105 494 344 META 0; +#X text 13 182 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; +#X text 13 160 AUTHOR Eric L. Singer; +#X text 13 6 KEYWORDS control; +#X text 13 50 DESCRIPTION bird flight and animal flock simulator; +#X text 13 72 INLET_0 bang dump mode reset number neighbors maxspeed minspeed center attract match avoid repel edgedist speed inertia accel prefdist flyrect attractpt; +#X text 13 116 OUTLET_0 list; +#X text 13 138 OUTLET_1 list; +#X text 13 28 LICENSE GPL v2; +#X restore 760 21 pd META; +#X obj 535 794 s \$0-boids-params; +#X text 156 633 ..., f 4; +#X obj 32 635 unpack; +#X floatatom 32 661 5 0 0 0 - - - 0; +#X floatatom 70 679 5 0 0 0 - - - 0; +#X obj 109 636 unpack; +#X floatatom 109 661 5 0 0 0 - - - 0; +#X floatatom 146 680 5 0 0 0 - - - 0; +#X obj 79 360 hradio 18 1 0 4 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X msg 53 316 dump; +#X msg 99 422 reset; +#X obj 32 228 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; +#N canvas 72 225 794 467 output-mode 0; +#X obj 198 262 unpack f f f f; +#X floatatom 190 288 5 0 0 0 - - - 0; +#X floatatom 220 314 5 0 0 0 - - - 0; +#X floatatom 252 294 5 0 0 0 - - - 0; +#X floatatom 278 317 5 0 0 0 - - - 0; +#X floatatom 343 254 5 0 0 0 - - - 0; +#X floatatom 373 279 5 0 0 0 - - - 0; +#X floatatom 405 260 5 0 0 0 - - - 0; +#X floatatom 431 283 5 0 0 0 - - - 0; +#X floatatom 516 281 5 0 0 0 - - - 0; +#X floatatom 557 281 5 0 0 0 - - - 0; +#X obj 233 84 list length; +#X obj 183 112 list prepend; +#X obj 186 66 t a a; +#X obj 109 205 unpack; +#X floatatom 109 230 5 0 0 0 - - - 0; +#X floatatom 146 249 5 0 0 0 - - - 0; +#X text 217 339 (1) new and old positions; +#X text 39 267 (0) new position only; +#X obj 186 17 inlet; +#X text 298 14 this patch shows the different output modes of the boids external.; +#X text 391 45 output mode:; +#X text 411 100 (1) new and old positions; +#X text 411 78 (0) new position only; +#X text 413 122 (2) new and old with speed \, azim \, elev (0); +#X text 412 142 (3) position and direction vectors; +#X text 221 359 (3) position and direction vectors; +#X obj 189 141 route 2 4 7; +#X obj 343 229 unpack f f f f f f f, f 25; +#X floatatom 603 281 5 0 0 0 - - - 0; +#X text 363 307 (2) new and old with speed \, azim \, elev (0); +#X connect 0 0 1 0; +#X connect 0 1 2 0; +#X connect 0 2 3 0; +#X connect 0 3 4 0; +#X connect 11 0 12 1; +#X connect 12 0 27 0; +#X connect 13 0 12 0; +#X connect 13 1 11 0; +#X connect 14 0 15 0; +#X connect 14 1 16 0; +#X connect 19 0 13 0; +#X connect 27 0 14 0; +#X connect 27 1 0 0; +#X connect 27 2 28 0; +#X connect 28 0 5 0; +#X connect 28 1 6 0; +#X connect 28 2 7 0; +#X connect 28 3 8 0; +#X connect 28 4 9 0; +#X connect 28 5 10 0; +#X connect 28 6 29 0; +#X restore 226 607 pd output-mode; +#X obj 193 635 unpack; +#X floatatom 193 661 5 0 0 0 - - - 0; +#X floatatom 231 679 5 0 0 0 - - - 0; +#X obj 32 572 route 0 1 2 3 4 10 15, f 27; +#X text 160 356 see [pd-output-mode]; +#X obj 109 453 r \$0-boids-params; +#X obj 536 738 pack; +#X obj 548 714 t b f; +#X text 98 308 Use the 'dump' message to output a list of the current parameter settings., f 42; +#X text 101 174 Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the X \, Y coordiantes for each boid., f 49; +#X text 51 254 The flight parameters can be changed with messages -->, f 28; +#X text 503 603 ATTRACTION POINT; +#X text 502 624 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; +#X obj 32 493 boids2d; +#X text 98 492 optional arguments: integer number of boids (default is 16); +#X text 165 508 next optional argument is mode (default is 0); +#X obj 32 175 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 32 200 metro 10; +#X obj 527 166 boids-params \$0; +#A saved flyrect -1 1 -1 1; +#A saved dimensions 2; +#A saved number 16; +#A saved neighbors 4; +#A saved maxspeed 1.5; +#A saved minspeed 1.2; +#A saved center 1.2; +#A saved attract 1.25; +#A saved match 0.3; +#A saved avoid 3.5; +#A saved repel 3.5; +#A saved edgedist 3; +#A saved speed 3; +#A saved inertia 4.5; +#A saved accel 2.5; +#A saved prefdist 1.5; +#X obj 547 69 declare -lib boids -path boids; +#X text 571 142 see helpfile for this:; +#X text 295 15 NOTE: this object is a 2-d only alias for [boids]. You can drop-in and replace it with [boids] from now on.; +#X obj 110 475 list trim; +#X connect 0 0 34 0; +#X connect 1 0 35 0; +#X connect 2 0 41 0; +#X connect 12 0 15 0; +#X connect 17 0 18 0; +#X connect 17 1 19 0; +#X connect 20 0 21 0; +#X connect 20 1 22 0; +#X connect 23 0 2 0; +#X connect 24 0 41 0; +#X connect 25 0 41 0; +#X connect 26 0 41 0; +#X connect 28 0 29 0; +#X connect 28 1 30 0; +#X connect 31 0 17 0; +#X connect 31 1 20 0; +#X connect 31 5 28 0; +#X connect 31 6 27 0; +#X connect 33 0 50 0; +#X connect 34 0 12 0; +#X connect 35 0 34 0; +#X connect 35 1 34 1; +#X connect 41 0 31 0; +#X connect 41 1 9 0; +#X connect 44 0 45 0; +#X connect 45 0 26 0; +#X connect 50 0 41 0; diff --git a/help/boids3d-help.pd b/help/boids3d-help.pd new file mode 100644 index 0000000..c1acf88 --- /dev/null +++ b/help/boids3d-help.pd @@ -0,0 +1,177 @@ +#N canvas 587 25 816 913 12; +#X declare -lib boids -path boids; +#X floatatom 481 677 5 0 0 0 - - - 0; +#X floatatom 525 675 5 0 0 0 - - - 0; +#X msg 80 386 mode \$1; +#X text 145 424 reset boids randomly inside flyrect; +#X text 36 840 (c) 1995-98 Eric L. Singer (eric@ericsinger.com); +#X text 25 73 Based on Simon Fraser's implementation of Craig Reynolds' Boids algorithm. Boids is free for non-commercial use; +#X text 25 109 Boids is a bird flight and animal flock simulator. It is based on the same algorithm which was used in Jurassic Park for the herding dinosaurs.; +#X text 29 772 For more information about the Boids algorithm \, see Craig Reynolds' Web site at http://www.red3d.com/cwr/boids/; +#X text 39 818 arguments: number of boids \, output mode; +#X obj 78 536 print dump; +#X obj 19 10 cnv 15 800 48 empty empty boids3d 15 20 2 24 #dce0c8 #404040 0; +#X text 37 863 float/2d/3d adaptation 08/2005 by a. sier / jasch; +#N canvas 88 105 494 344 META 0; +#X text 13 182 HELP_PATCH_AUTHORS "pd meta" information added by Jonathan Wilkes for Pd version 0.42.; +#X text 13 160 AUTHOR Eric L. Singer; +#X text 13 6 KEYWORDS control; +#X text 13 50 DESCRIPTION bird flight and animal flock simulator; +#X text 13 72 INLET_0 bang dump mode reset number neighbors maxspeed minspeed center attract match avoid repel edgedist speed inertia accel prefdist flyrect attractpt; +#X text 13 116 OUTLET_0 list; +#X text 13 138 OUTLET_1 list; +#X text 13 28 LICENSE GPL v2; +#X restore 760 21 pd META; +#X obj 510 777 s \$0-boids-params; +#X text 225 654 ..., f 4; +#X floatatom 24 677 5 0 0 0 - - - 0; +#X floatatom 62 695 5 0 0 0 - - - 0; +#X floatatom 127 675 5 0 0 0 - - - 0; +#X floatatom 164 694 5 0 0 0 - - - 0; +#X obj 79 360 hradio 18 1 0 4 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000 0; +#X msg 53 316 dump; +#X msg 99 422 reset; +#X obj 32 228 bng 18 250 50 0 empty empty empty 0 -9 0 10 #fcfcfc #000000 #000000; +#N canvas 55 187 794 467 output-mode 0; +#X floatatom 156 318 5 0 0 0 - - - 0; +#X floatatom 186 344 5 0 0 0 - - - 0; +#X floatatom 219 367 5 0 0 0 - - - 0; +#X floatatom 252 325 5 0 0 0 - - - 0; +#X floatatom 343 254 5 0 0 0 - - - 0; +#X floatatom 373 279 5 0 0 0 - - - 0; +#X floatatom 390 302 5 0 0 0 - - - 0; +#X floatatom 457 297 5 0 0 0 - - - 0; +#X floatatom 468 321 5 0 0 0 - - - 0; +#X floatatom 492 351 5 0 0 0 - - - 0; +#X obj 252 63 list length; +#X obj 183 112 list prepend; +#X obj 186 66 t a a; +#X floatatom 49 228 5 0 0 0 - - - 0; +#X floatatom 86 247 5 0 0 0 - - - 0; +#X text 141 407 (1) new and old positions; +#X text 39 267 (0) new position only; +#X obj 186 17 inlet; +#X text 298 14 this patch shows the different output modes of the boids external.; +#X text 389 99 (1) new and old positions; +#X text 389 77 (0) new position only; +#X obj 47 203 unpack f f f; +#X floatatom 129 228 5 0 0 0 - - - 0; +#X obj 198 262 unpack f f f f f f; +#X floatatom 274 354 5 0 0 0 - - - 0; +#X floatatom 300 380 5 0 0 0 - - - 0; +#X floatatom 552 307 5 0 0 0 - - - 0; +#X floatatom 563 331 5 0 0 0 - - - 0; +#X floatatom 587 361 5 0 0 0 - - - 0; +#X obj 343 229 unpack f f f f f f f f f, f 33; +#X obj 189 141 route 3 6 9; +#X text 391 121 (2) new and old with speed \, azi \, elev; +#X text 391 141 (3) position and direction vectors; +#X text 140 433 (3) position and direction vectors; +#X text 371 400 (2) new and old with speed \, azi \, elev; +#X connect 10 0 11 1; +#X connect 11 0 30 0; +#X connect 12 0 11 0; +#X connect 12 1 10 0; +#X connect 17 0 12 0; +#X connect 21 0 13 0; +#X connect 21 1 14 0; +#X connect 21 2 22 0; +#X connect 23 0 0 0; +#X connect 23 1 1 0; +#X connect 23 2 2 0; +#X connect 23 3 3 0; +#X connect 23 4 24 0; +#X connect 23 5 25 0; +#X connect 29 0 4 0; +#X connect 29 1 5 0; +#X connect 29 2 6 0; +#X connect 29 3 7 0; +#X connect 29 4 8 0; +#X connect 29 5 9 0; +#X connect 29 6 26 0; +#X connect 29 7 27 0; +#X connect 29 8 28 0; +#X connect 30 0 21 0; +#X connect 30 1 23 0; +#X connect 30 2 29 0; +#X restore 251 605 pd output-mode; +#X floatatom 279 690 5 0 0 0 - - - 0; +#X floatatom 317 708 5 0 0 0 - - - 0; +#X obj 32 572 route 0 1 2 3 4 10 15, f 27; +#X text 161 362 see [pd-output-mode]; +#X obj 109 453 r \$0-boids-params; +#X obj 523 697 t b f; +#X text 98 308 Use the 'dump' message to output a list of the current parameter settings., f 42; +#X text 51 254 The flight parameters can be changed with messages -->, f 28; +#X text 477 592 ATTRACTION POINT; +#X text 476 613 Usually \, the attraction point is what can be "moved" to cause the entire flock to follow it, f 39; +#X text 98 492 optional arguments: integer number of boids (default is 16); +#X text 165 508 next optional argument is mode (default is 0); +#X obj 32 175 tgl 20 0 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 0 1; +#X obj 32 200 metro 10; +#X obj 32 493 boids3d; +#X obj 24 651 unpack f f f; +#X obj 127 650 unpack f f f; +#X obj 279 664 unpack f f f; +#X floatatom 102 703 5 0 0 0 - - - 0; +#X floatatom 209 701 5 0 0 0 - - - 0; +#X floatatom 373 692 5 0 0 0 - - - 0; +#X msg 510 747 attractpt \$1 \$2 \$3; +#X text 621 681 point to which boids are attracted (x/y/z), f 21; +#X floatatom 577 677 5 0 0 0 - - - 0; +#X obj 575 699 t b f; +#X obj 511 721 pack f f f; +#X text 101 174 Each time Boids receives a bang \, it calculates and outputs the new positions of the boids. The output consists of the X \, Y \, Z coordiantes for each boid., f 49; +#X obj 499 139 boids-params \$0; +#A saved flyrect -1 1 -1 1; +#A saved dimensions 2; +#A saved number 16; +#A saved neighbors 4; +#A saved maxspeed 1.5; +#A saved minspeed 1.2; +#A saved center 1.2; +#A saved attract 1.25; +#A saved match 0.3; +#A saved avoid 3.5; +#A saved repel 3.5; +#A saved edgedist 3; +#A saved speed 3; +#A saved inertia 4.5; +#A saved accel 2.5; +#A saved prefdist 1.5; +#X obj 501 80 declare -lib boids -path boids; +#X obj 110 474 list trim; +#X text 313 7 NOTE: this object is a 3d-only version of [boids] and won't take the "dimensions" message. You can drop-in and replace it with [boids] from now on.; +#X connect 0 0 49 0; +#X connect 1 0 29 0; +#X connect 2 0 38 0; +#X connect 19 0 2 0; +#X connect 20 0 38 0; +#X connect 21 0 38 0; +#X connect 22 0 38 0; +#X connect 26 0 39 0; +#X connect 26 1 40 0; +#X connect 26 5 41 0; +#X connect 26 6 23 0; +#X connect 28 0 53 0; +#X connect 29 0 49 0; +#X connect 29 1 49 1; +#X connect 36 0 37 0; +#X connect 37 0 22 0; +#X connect 38 0 26 0; +#X connect 38 1 9 0; +#X connect 39 0 15 0; +#X connect 39 1 16 0; +#X connect 39 2 42 0; +#X connect 40 0 17 0; +#X connect 40 1 18 0; +#X connect 40 2 43 0; +#X connect 41 0 24 0; +#X connect 41 1 25 0; +#X connect 41 2 44 0; +#X connect 45 0 13 0; +#X connect 47 0 48 0; +#X connect 48 0 49 0; +#X connect 48 1 49 2; +#X connect 49 0 45 0; +#X connect 53 0 38 0; diff --git a/src/boid_params.c b/src/boid_params.c new file mode 100644 index 0000000..ce836b2 --- /dev/null +++ b/src/boid_params.c @@ -0,0 +1,160 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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. +*/ +#include "boid_params.h" + +static t_float boids_clip_min(t_float value, t_float min) +{ + return value < min ? min : value; +} + +static t_float boids_clip01(t_float value) +{ + return value < 0.0 ? 0.0 : value > 1.0 ? 1.0 : value; +} + +void boid_params_refresh(t_boid_params *x) +{ + if (!x) + return; + + x->x_speed_min = boids_clip_min(x->x_speed_min, 0.000001); + x->x_speed_max = boids_clip_min(x->x_speed_max, x->x_speed_min); + x->x_factor_accel = boids_clip_min(x->x_factor_accel, 0.000001); + x->x_factor_inertia = boids_clip01(x->x_factor_inertia); + x->x_distance_edge = boids_clip_min(x->x_distance_edge, 0.000001); + x->x_pref_dist = boids_clip_min(x->x_pref_dist, 0.000001); + + x->x_pref_dist_sqr = x->x_pref_dist * x->x_pref_dist; + x->x_factor_accel_inv = 1.0 / x->x_factor_accel; + x->x_factor_inertia_inv = 1.0 - x->x_factor_inertia; +} + +t_boid_params *boid_params_new(void) +{ + t_boid_params *x = (t_boid_params *)getbytes(sizeof(*x)); + if (!x) + return NULL; + + x->x_speed_min = 0.15; + x->x_speed_max = 0.25; + + /* Defaults are tuned for normalized [-1, 1] bounds. The old defaults + pulled every boid to the origin via attract=0.3, which caused clumping. */ + x->x_weight_center = 0.03; + x->x_weight_attract = 0.0; + x->x_weight_match = 0.15; + x->x_weight_avoid = 0.75; + x->x_weight_walls = 1.0; + + x->x_factor_speedup = 0.1; + x->x_factor_inertia = 0.85; + x->x_factor_accel = 0.05; + + x->x_distance_edge = 0.25; + x->x_pref_dist = 0.25; + + boid_params_refresh(x); + return x; +} + +void boid_params_free(t_boid_params *x) +{ + if (!x) + return; + + freebytes(x, sizeof(*x)); +} + +void boid_params_dump(t_boid_params *x, t_outlet *out) +{ + if (!x || !out) + return; + + t_atom argv; + + SETFLOAT(&argv, x->x_speed_min); + outlet_anything(out, gensym("minspeed"), 1, &argv); + + SETFLOAT(&argv, x->x_speed_max); + outlet_anything(out, gensym("maxspeed"), 1, &argv); + + SETFLOAT(&argv, x->x_weight_center); + outlet_anything(out, gensym("center"), 1, &argv); + + SETFLOAT(&argv, x->x_weight_attract); + outlet_anything(out, gensym("attract"), 1, &argv); + + SETFLOAT(&argv, x->x_weight_match); + outlet_anything(out, gensym("match"), 1, &argv); + + SETFLOAT(&argv, x->x_weight_avoid); + outlet_anything(out, gensym("avoid"), 1, &argv); + + SETFLOAT(&argv, x->x_weight_walls); + outlet_anything(out, gensym("repel"), 1, &argv); + + SETFLOAT(&argv, x->x_distance_edge); + outlet_anything(out, gensym("edgedist"), 1, &argv); + + SETFLOAT(&argv, x->x_factor_speedup * 100.0); + outlet_anything(out, gensym("speed"), 1, &argv); + + SETFLOAT(&argv, x->x_factor_inertia); + outlet_anything(out, gensym("inertia"), 1, &argv); + + SETFLOAT(&argv, x->x_factor_accel); + outlet_anything(out, gensym("accel"), 1, &argv); + + SETFLOAT(&argv, x->x_pref_dist); + outlet_anything(out, gensym("prefdist"), 1, &argv); +} + +void boid_params_set_speed_min(t_boid_params *x, t_floatarg f) +{ + x->x_speed_min = f; + boid_params_refresh(x); +} + +void boid_params_set_speed_max(t_boid_params *x, t_floatarg f) +{ + x->x_speed_max = f; + boid_params_refresh(x); +} + +void boid_params_set_factor_speedup(t_boid_params *x, t_floatarg f) +{ + x->x_factor_speedup = f / 100.0; + boid_params_refresh(x); +} + +void boid_params_set_factor_inertia(t_boid_params *x, t_floatarg f) +{ + x->x_factor_inertia = f; + boid_params_refresh(x); +} + +void boid_params_set_factor_accel(t_boid_params *x, t_floatarg f) +{ + x->x_factor_accel = f; + boid_params_refresh(x); +} + +void boid_params_set_pref_dist(t_boid_params *x, t_floatarg f) +{ + x->x_pref_dist = f; + boid_params_refresh(x); +} + +void boid_params_set_edge_dist(t_boid_params *x, t_floatarg f) +{ + x->x_distance_edge = f; + boid_params_refresh(x); +} diff --git a/src/boid_params.h b/src/boid_params.h new file mode 100644 index 0000000..7b5ab65 --- /dev/null +++ b/src/boid_params.h @@ -0,0 +1,53 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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. +*/ +#ifndef BOID_PARAMS_H +#define BOID_PARAMS_H + +#include "m_pd.h" + +typedef struct _boid_params +{ + t_float x_speed_min; + t_float x_speed_max; + + t_float x_weight_center; + t_float x_weight_attract; + t_float x_weight_match; + t_float x_weight_avoid; + t_float x_weight_walls; + + t_float x_factor_speedup; + t_float x_factor_inertia; + t_float x_factor_accel; + + t_float x_distance_edge; + t_float x_pref_dist; + + /* cached/derived values */ + t_float x_factor_accel_inv; + t_float x_pref_dist_sqr; + t_float x_factor_inertia_inv; +} t_boid_params; + +t_boid_params *boid_params_new(void); +void boid_params_free(t_boid_params *x); +void boid_params_dump(t_boid_params *x, t_outlet *out); +void boid_params_refresh(t_boid_params *x); + +void boid_params_set_speed_min(t_boid_params *x, t_floatarg f); +void boid_params_set_speed_max(t_boid_params *x, t_floatarg f); +void boid_params_set_factor_speedup(t_boid_params *x, t_floatarg f); +void boid_params_set_factor_inertia(t_boid_params *x, t_floatarg f); +void boid_params_set_factor_accel(t_boid_params *x, t_floatarg f); +void boid_params_set_pref_dist(t_boid_params *x, t_floatarg f); +void boid_params_set_edge_dist(t_boid_params *x, t_floatarg f); + +#endif diff --git a/src/boids.c b/src/boids.c new file mode 100644 index 0000000..7c7d52d --- /dev/null +++ b/src/boids.c @@ -0,0 +1,937 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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. +*/ +#include "boids.h" +#include "m_pd.h" +#include +#include + +#define BOIDS_EPS ((t_float)1e-12) + +static t_class *boids3d_class, *boids2d_class, *boids_class; + +static t_newmethod boids_newmethod_cast(void *(*fn)(t_floatarg, t_floatarg)) +{ +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif + t_newmethod result = (t_newmethod)fn; +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + return result; +} + +/* ----------------------------- force vectors ------------------------------ */ + +t_boid_forces *boid_forces_new(size_t dimensions) +{ + t_boid_forces *forces = (t_boid_forces *)getbytes(sizeof(*forces)); + if (!forces) + return NULL; + + vec_alloc(&forces->x_avoid_neighbors, dimensions); + vec_alloc(&forces->x_avoid_walls, dimensions); + vec_alloc(&forces->x_go_attract, dimensions); + vec_alloc(&forces->x_go_center, dimensions); + vec_alloc(&forces->x_match_neighbors, dimensions); + return forces; +} + +void boid_forces_clear(t_boid_forces *x) +{ + if (!x) + return; + + vec_fill(&x->x_avoid_neighbors, 0.0); + vec_fill(&x->x_avoid_walls, 0.0); + vec_fill(&x->x_go_attract, 0.0); + vec_fill(&x->x_go_center, 0.0); + vec_fill(&x->x_match_neighbors, 0.0); +} + +void boid_forces_free(t_boid_forces *x) +{ + if (!x) + return; + + vec_clear(&x->x_avoid_neighbors); + vec_clear(&x->x_avoid_walls); + vec_clear(&x->x_go_attract); + vec_clear(&x->x_go_center); + vec_clear(&x->x_match_neighbors); + freebytes(x, sizeof(*x)); +} + +static t_float boids_force_at(t_boid_params *params, t_boid_forces *forces, + size_t d) +{ + return params->x_weight_center * forces->x_go_center.x[d] + + params->x_weight_attract * forces->x_go_attract.x[d] + + params->x_weight_match * forces->x_match_neighbors.x[d] + + params->x_weight_avoid * forces->x_avoid_neighbors.x[d] + + params->x_weight_walls * forces->x_avoid_walls.x[d]; +} + +void boid_direction_update(t_vec_state *direction, t_boid_params *params, + t_boid_forces *forces) +{ + t_vec *old = &direction->x_old; + t_vec *new = &direction->x_new; + + for (size_t d = 0; d < new->x_dimensions; ++d) + new->x[d] = old->x[d] * params->x_factor_inertia + + boids_force_at(params, forces, d) * + params->x_factor_inertia_inv; + + if (!vec_normalize(new)) + { + vec_copy(new, old); + if (!vec_normalize(new)) + vec_random_unit(new); + } +} + +/* ---------------------------- helper functions ---------------------------- */ + +static t_float boids_clip(t_float value, t_float min, t_float max) +{ + return value < min ? min : value > max ? max : value; +} + +static void boid_seek(const t_boid *x, const t_vec *seek, t_vec *target) +{ + if (!x || !seek || !target) + return; + + for (size_t d = 0; d < seek->x_dimensions; ++d) + target->x[d] = seek->x[d] - x->x_position.x_old.x[d]; + + vec_normalize(target); +} + +static void boid_compute_neighbor_distances(t_boid *x) +{ + t_boids *flock = x->x_flock; + size_t num_boids = flock->x_num_boids; + size_t max_neighbors = flock->x_max_neighbors; + + if (!x->x_neighbors || num_boids <= 1 || max_neighbors == 0) + return; + + if (max_neighbors > num_boids - 1) + max_neighbors = num_boids - 1; + + for (size_t i = 0; i < max_neighbors; ++i) + { + x->x_neighbors[i].x_boid = NULL; + x->x_neighbors[i].x_distance = (t_float)kMaxLong; + x->x_neighbors[i].x_next = + (i + 1 < max_neighbors) ? &x->x_neighbors[i + 1] : NULL; + } + + for (size_t i = 0; i < num_boids; ++i) + { + t_boid *candidate = &flock->x_boid[i]; + if (candidate == x) + continue; + + t_float distance = vec_square_distance(&x->x_position.x_old, + &candidate->x_position.x_old); + + if (distance < x->x_neighbors[max_neighbors - 1].x_distance) + { + size_t j = max_neighbors - 1; + + while (j > 0 && distance < x->x_neighbors[j - 1].x_distance) + { + x->x_neighbors[j].x_boid = x->x_neighbors[j - 1].x_boid; + x->x_neighbors[j].x_distance = + x->x_neighbors[j - 1].x_distance; + --j; + } + + x->x_neighbors[j].x_boid = candidate; + x->x_neighbors[j].x_distance = distance; + } + } +} + +static int boid_infront(t_boid *boid, t_boid *neighbor) +{ + t_float dot = vec_dot_offset_dir(&boid->x_position.x_old, + &neighbor->x_position.x_old, + &boid->x_direction.x_old); + return dot > 0.0; +} + +static void boid_add_zero_distance_escape(t_boid *x, t_vec *avoid, + t_float strength) +{ + /* If two boids occupy exactly the same position, there is no usable + position delta. Push opposite to the current direction as a stable + deterministic fallback. */ + vec_add_scaled(avoid, &x->x_direction.x_old, -strength); +} + +static t_float boid_match_and_avoid_neighbors(t_boid *x, + t_vec *match_neighbors, + t_vec *avoid_neighbors) +{ + t_boid_params *params = x->x_flock->x_params; + t_float pref_dist = params->x_pref_dist; + t_float pref_dist_sqr = params->x_pref_dist_sqr; + t_float speed = x->x_speed; + size_t num_neighbors = 0; + size_t num_close = 0; + size_t close_in_front = 0; + size_t close_behind = 0; + + for (t_neighbor *neighbor = x->x_neighbors; neighbor; + neighbor = neighbor->x_next) + { + t_boid *other = neighbor->x_boid; + t_float dist_sqr = neighbor->x_distance; + + if (!other) + continue; + + ++num_neighbors; + vec_add(match_neighbors, &other->x_direction.x_old); + + if (dist_sqr < pref_dist_sqr) + { + t_float dist = sqrt(dist_sqr); + t_float strength = (pref_dist - dist) / pref_dist; + + if (dist <= BOIDS_EPS) + boid_add_zero_distance_escape(x, avoid_neighbors, strength); + else + vec_add_delta_unit_scaled(avoid_neighbors, &x->x_position.x_old, + &other->x_position.x_old, strength); + + ++num_close; + if (boid_infront(x, other)) + ++close_in_front; + else + ++close_behind; + } + } + + if (num_neighbors) + { + vec_average(match_neighbors, num_neighbors); + vec_normalize(match_neighbors); + } + + if (num_close) + { + vec_average(avoid_neighbors, num_close); + + /* Simple, bounded speed response: slow down for close boids in front, + speed up slightly if crowded from behind. */ + if (close_in_front >= close_behind) + speed *= 1.0 - params->x_factor_accel; + else + speed *= 1.0 + params->x_factor_accel; + } + + return boids_clip(speed, params->x_speed_min, params->x_speed_max); +} + +static void boid_avoid_walls(t_boid *x, t_vec *target, t_float distance_edge) +{ + t_boids *flock = x->x_flock; + + vec_fill(target, 0.0); + + for (size_t d = 0; d < flock->x_dimensions; ++d) + { + t_float lo = flock->x_bounds[d * 2]; + t_float hi = flock->x_bounds[d * 2 + 1]; + t_float span = hi - lo; + t_float edge = distance_edge; + t_float pos = x->x_position.x_old.x[d]; + + if (span <= 0.0) + continue; + + if (edge > span * 0.5) + edge = span * 0.5; + + if (pos < lo + edge) + target->x[d] += (lo + edge - pos) / edge; + else if (pos > hi - edge) + target->x[d] -= (pos - (hi - edge)) / edge; + } +} + +static void boid_keep_inside_bounds(t_boid *b) +{ + t_boids *flock = b->x_flock; + + for (size_t d = 0; d < flock->x_dimensions; ++d) + { + t_float lo = flock->x_bounds[d * 2]; + t_float hi = flock->x_bounds[d * 2 + 1]; + + if (b->x_position.x_new.x[d] < lo) + { + b->x_position.x_new.x[d] = lo; + b->x_direction.x_new.x[d] = fabs(b->x_direction.x_new.x[d]); + } + else if (b->x_position.x_new.x[d] > hi) + { + b->x_position.x_new.x[d] = hi; + b->x_direction.x_new.x[d] = -fabs(b->x_direction.x_new.x[d]); + } + } + + vec_normalize(&b->x_direction.x_new); +} + +static void boids_step(t_boids *x) +{ + if (!x || x->x_num_boids == 0) + return; + + for (size_t i = 0; i < x->x_num_boids; ++i) + { + vec_state_step(&x->x_boid[i].x_position); + vec_state_step(&x->x_boid[i].x_direction); + } + + vec_fill(&x->x_position_center, 0.0); + for (size_t i = 0; i < x->x_num_boids; ++i) + vec_add(&x->x_position_center, &x->x_boid[i].x_position.x_old); + vec_average(&x->x_position_center, x->x_num_boids); + + for (size_t i = 0; i < x->x_num_boids; ++i) + { + t_boid *boid = &x->x_boid[i]; + t_boid_forces *forces = x->x_forces; + + boid_forces_clear(forces); + + if (x->x_max_neighbors > 0) + { + boid_compute_neighbor_distances(boid); + boid->x_speed = boid_match_and_avoid_neighbors( + boid, &forces->x_match_neighbors, &forces->x_avoid_neighbors); + } + + boid_seek(boid, &x->x_position_center, &forces->x_go_center); + boid_seek(boid, &x->x_position_attract, &forces->x_go_attract); + boid_avoid_walls(boid, &forces->x_avoid_walls, + x->x_params->x_distance_edge); + + boid_direction_update(&boid->x_direction, x->x_params, forces); + + vec_copy(&boid->x_position.x_new, &boid->x_position.x_old); + vec_add_scaled(&boid->x_position.x_new, &boid->x_direction.x_new, + boid->x_speed * x->x_params->x_factor_speedup); + + boid_keep_inside_bounds(boid); + } +} + +/* -------------------------------- outlets --------------------------------- */ + +static void outlet_newpos(t_boids *x) +{ + size_t argc = x->x_dimensions + 1; + t_atom *argv = (t_atom *)getbytes(sizeof(*argv) * argc); + + if (!argv) + return; + + for (size_t i = 0; i < x->x_num_boids; ++i) + { + SETFLOAT(argv + 0, (t_float)i); + + for (size_t d = 0; d < x->x_dimensions; ++d) + SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new.x[d]); + + outlet_list(x->x_out1, gensym("list"), (int)argc, argv); + } + + freebytes(argv, sizeof(*argv) * argc); +} + +static void outlet_newold(t_boids *x) +{ + size_t argc = 1 + (2 * x->x_dimensions); + t_atom *argv = (t_atom *)getbytes(sizeof(*argv) * argc); + + if (!argv) + return; + + for (size_t i = 0; i < x->x_num_boids; ++i) + { + SETFLOAT(argv + 0, (t_float)i); + + for (size_t d = 0; d < x->x_dimensions; ++d) + SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new.x[d]); + + for (size_t d = 0; d < x->x_dimensions; ++d) + SETFLOAT(argv + 1 + x->x_dimensions + d, + x->x_boid[i].x_position.x_old.x[d]); + + outlet_list(x->x_out1, gensym("list"), (int)argc, argv); + } + + freebytes(argv, sizeof(*argv) * argc); +} + +static void outlet_all(t_boids *x) +{ + t_atom out[10]; + int has_z = (x->x_dimensions >= 3); + + if (x->x_dimensions < 2) + return; + + for (size_t i = 0; i < x->x_num_boids; ++i) + { + t_float new_x = x->x_boid[i].x_position.x_new.x[0]; + t_float new_y = x->x_boid[i].x_position.x_new.x[1]; + t_float old_x = x->x_boid[i].x_position.x_old.x[0]; + t_float old_y = x->x_boid[i].x_position.x_old.x[1]; + t_float delta_x = new_x - old_x; + t_float delta_y = new_y - old_y; + t_float delta_z = 0.0; + t_float new_z = 0.0; + t_float old_z = 0.0; + + if (has_z) + { + new_z = x->x_boid[i].x_position.x_new.x[2]; + old_z = x->x_boid[i].x_position.x_old.x[2]; + delta_z = new_z - old_z; + } + + t_float speed = + sqrt(delta_x * delta_x + delta_y * delta_y + delta_z * delta_z); + t_float azi = atan2(delta_y, delta_x) * R2D; + t_float ele = has_z ? atan2(delta_z, sqrt(delta_x * delta_x + + delta_y * delta_y)) * + R2D + : 0.0; + + SETFLOAT(out + 0, (t_float)i); + + if (!has_z) + { + SETFLOAT(out + 1, new_x); + SETFLOAT(out + 2, new_y); + SETFLOAT(out + 3, old_x); + SETFLOAT(out + 4, old_y); + SETFLOAT(out + 5, speed); + SETFLOAT(out + 6, azi); + SETFLOAT(out + 7, ele); + outlet_list(x->x_out1, gensym("list"), 8, out); + } + else + { + SETFLOAT(out + 1, new_x); + SETFLOAT(out + 2, new_y); + SETFLOAT(out + 3, new_z); + SETFLOAT(out + 4, old_x); + SETFLOAT(out + 5, old_y); + SETFLOAT(out + 6, old_z); + SETFLOAT(out + 7, speed); + SETFLOAT(out + 8, azi); + SETFLOAT(out + 9, ele); + outlet_list(x->x_out1, gensym("list"), 10, out); + } + } +} + +static void outlet_posvel(t_boids *x) +{ + size_t argc = 1 + (2 * x->x_dimensions); + t_atom *argv = (t_atom *)getbytes(sizeof(*argv) * argc); + + if (!argv) + return; + + for (size_t i = 0; i < x->x_num_boids; ++i) + { + SETFLOAT(argv + 0, (t_float)i); + + for (size_t d = 0; d < x->x_dimensions; ++d) + SETFLOAT(argv + 1 + d, x->x_boid[i].x_position.x_new.x[d]); + + for (size_t d = 0; d < x->x_dimensions; ++d) + SETFLOAT(argv + 1 + x->x_dimensions + d, + x->x_boid[i].x_direction.x_new.x[d]); + + outlet_list(x->x_out1, gensym("list"), (int)argc, argv); + } + + freebytes(argv, sizeof(*argv) * argc); +} + +/* ---------------------------- boids methods ------------------------------- */ + +static void boids_bang(t_boids *x) +{ + boids_step(x); + + switch (x->x_mode) + { + case BOID_NEWPOS: + default: + outlet_newpos(x); + break; + case BOID_NEWOLD: + outlet_newold(x); + break; + case BOID_ALL: + outlet_all(x); + break; + case BOID_POSVEL: + outlet_posvel(x); + break; + } +} + +static void boids_dump(t_boids *x) +{ + size_t nbytes = sizeof(t_atom) * 2 * x->x_dimensions; + t_atom *argv = (t_atom *)getbytes(nbytes); + + if (!argv) + return; + + SETFLOAT(argv, x->x_max_neighbors); + outlet_anything(x->x_out2, gensym("neighbors"), 1, argv); + + boid_params_dump(x->x_params, x->x_out2); + + for (size_t i = 0; i < 2 * x->x_dimensions; ++i) + SETFLOAT(argv + i, x->x_bounds[i]); + outlet_anything(x->x_out2, gensym("flyrect"), 2 * x->x_dimensions, argv); + + for (size_t i = 0; i < x->x_dimensions; ++i) + SETFLOAT(argv + i, x->x_position_attract.x[i]); + outlet_anything(x->x_out2, gensym("attractpt"), x->x_dimensions, argv); + + for (size_t i = 0; i < x->x_dimensions; ++i) + SETFLOAT(argv + i, x->x_position_center.x[i]); + outlet_anything(x->x_out2, gensym("centerpt"), x->x_dimensions, argv); + + SETFLOAT(argv, x->x_mode); + outlet_anything(x->x_out2, gensym("mode"), 1, argv); + + SETFLOAT(argv, x->x_num_boids); + outlet_anything(x->x_out2, gensym("number"), 1, argv); + + SETFLOAT(argv, x->x_dimensions); + outlet_anything(x->x_out2, gensym("dimensions"), 1, argv); + + freebytes(argv, nbytes); +} + +static void boids_num_neighbors(t_boids *x, t_floatarg f) +{ + size_t n = f <= 0.0 ? 0 : (size_t)f; + size_t max = x->x_num_boids > 0 ? x->x_num_boids - 1 : 0; + x->x_max_neighbors = n > max ? max : n; +} + +static void boids_minSpeed(t_boids *x, t_floatarg f) +{ + boid_params_set_speed_min(x->x_params, f); +} + +static void boids_maxSpeed(t_boids *x, t_floatarg f) +{ + boid_params_set_speed_max(x->x_params, f); +} + +static void boids_centerWeight(t_boids *x, t_floatarg f) +{ + x->x_params->x_weight_center = f; +} + +static void boids_attractWeight(t_boids *x, t_floatarg f) +{ + x->x_params->x_weight_attract = f; +} + +static void boids_matchWeight(t_boids *x, t_floatarg f) +{ + x->x_params->x_weight_match = f; +} + +static void boids_avoidWeight(t_boids *x, t_floatarg f) +{ + x->x_params->x_weight_avoid = f; +} + +static void boids_wallsWeight(t_boids *x, t_floatarg f) +{ + x->x_params->x_weight_walls = f; +} + +static void boids_edgeDist(t_boids *x, t_floatarg f) +{ + boid_params_set_edge_dist(x->x_params, f); +} + +static void boids_speedupFactor(t_boids *x, t_floatarg f) +{ + boid_params_set_factor_speedup(x->x_params, f); +} + +static void boids_inertiaFactor(t_boids *x, t_floatarg f) +{ + boid_params_set_factor_inertia(x->x_params, f); +} + +static void boids_accelFactor(t_boids *x, t_floatarg f) +{ + boid_params_set_factor_accel(x->x_params, f); +} + +static void boids_prefDist(t_boids *x, t_floatarg f) +{ + boid_params_set_pref_dist(x->x_params, f); +} + +static void boids_bounds(t_boids *x, t_symbol *s, int argc, t_atom *argv) +{ + (void)s; + + size_t nbounds = 2 * x->x_dimensions; + + for (size_t i = 0; i < nbounds && i < (size_t)argc; ++i) + x->x_bounds[i] = atom_getfloat(argv + i); + + for (size_t d = 0; d < x->x_dimensions; ++d) + { + t_float *lo = &x->x_bounds[d * 2]; + t_float *hi = &x->x_bounds[d * 2 + 1]; + if (*hi < *lo) + { + t_float tmp = *lo; + *lo = *hi; + *hi = tmp; + } + if (*hi == *lo) + *hi = *lo + 1.0; + } + + if ((size_t)argc > nbounds) + { + startpost("Ignoring extra args"); + postatom(argc - (int)nbounds, argv + nbounds); + endpost(); + } +} + +static void boids_position_attract(t_boids *x, t_symbol *s, int argc, + t_atom *argv) +{ + (void)s; + vec_update(&x->x_position_attract, argc, argv); +} + +/* -------------------------- memory management ----------------------------- */ + +static void boids_bounds_free(t_boids *x) +{ + if (!x->x_bounds) + return; + + freebytes(x->x_bounds, sizeof(*x->x_bounds) * 2 * x->x_dimensions); + x->x_bounds = NULL; +} + +static void boids_vecs_free(t_boids *x) +{ + vec_clear(&x->x_position_center); + vec_clear(&x->x_position_attract); +} + +static void boids_boid_free(t_boids *x) +{ + if (!x->x_boid) + return; + + for (size_t i = 0; i < x->x_num_boids; ++i) + { + t_boid *boid = &x->x_boid[i]; + + if (boid->x_neighbors) + { + freebytes(boid->x_neighbors, + sizeof(*boid->x_neighbors) * (x->x_num_boids - 1)); + boid->x_neighbors = NULL; + } + + vec_state_clear(&boid->x_position); + vec_state_clear(&boid->x_direction); + boid->x_next = NULL; + boid->x_flock = NULL; + } + + freebytes(x->x_boid, sizeof(*x->x_boid) * x->x_num_boids); + x->x_boid = NULL; + x->x_num_boids = 0; +} + +static void boids_free(t_boids *x) +{ + boids_boid_free(x); + boids_bounds_free(x); + boids_vecs_free(x); + boid_params_free(x->x_params); + boid_forces_free(x->x_forces); + x->x_params = NULL; + x->x_forces = NULL; +} + +/* ---------------------------- initialization ------------------------------ */ + +static void boids_reset(t_boids *x) +{ + if (!x || !x->x_boid) + return; + + for (size_t i = 0; i < x->x_num_boids; ++i) + { + t_boid *boid = &x->x_boid[i]; + + vec_state_random_range(&boid->x_position, x->x_bounds); + vec_state_random_unit(&boid->x_direction); + boid->x_speed = + (x->x_params->x_speed_max + x->x_params->x_speed_min) * 0.5; + } +} + +static t_boid *boid_list_new(size_t num_boids, t_boids *flock) +{ + if (!num_boids) + return NULL; + + t_boid *boid_list = (t_boid *)getbytes(num_boids * sizeof(*boid_list)); + if (!boid_list) + return NULL; + + for (size_t i = 0; i < num_boids; ++i) + { + t_boid *b = &boid_list[i]; + memset(b, 0, sizeof(*b)); + + b->x_flock = flock; + b->x_next = (i + 1 < num_boids) ? &boid_list[i + 1] : NULL; + b->x_speed = 0.0; + + vec_state_alloc(&b->x_position, flock->x_dimensions); + vec_state_alloc(&b->x_direction, flock->x_dimensions); + + if (num_boids > 1) + { + b->x_neighbors = (t_neighbor *)getbytes((num_boids - 1) * + sizeof(*b->x_neighbors)); + if (b->x_neighbors) + { + for (size_t j = 0; j < num_boids - 1; ++j) + { + b->x_neighbors[j].x_next = + (j + 1 < num_boids - 1) ? &b->x_neighbors[j + 1] + : NULL; + b->x_neighbors[j].x_boid = NULL; + b->x_neighbors[j].x_distance = (t_float)kMaxLong; + } + } + } + } + + return boid_list; +} + +static void boids_bounds_alloc(t_boids *x) +{ + size_t nbounds = 2 * x->x_dimensions; + x->x_bounds = (t_float *)getbytes(sizeof(*x->x_bounds) * nbounds); + + for (size_t d = 0; d < x->x_dimensions; ++d) + { + x->x_bounds[d * 2] = -1.0; + x->x_bounds[d * 2 + 1] = 1.0; + } +} + +static void boids_init(t_boids *x, size_t dimensions, size_t num_boids) +{ + boids_free(x); + + x->x_dimensions = vec_dimensions_clamp(dimensions); + x->x_num_boids = num_boids; + + x->x_params = boid_params_new(); + boids_num_neighbors(x, 4.0); + + boids_bounds_alloc(x); + vec_alloc(&x->x_position_center, x->x_dimensions); + vec_alloc(&x->x_position_attract, x->x_dimensions); + x->x_forces = boid_forces_new(x->x_dimensions); + x->x_boid = boid_list_new(x->x_num_boids, x); + + boids_reset(x); +} + +static void boids_reinit(t_boids *x) +{ + boids_init(x, x->x_dimensions, x->x_num_boids); +} + +static void boids_dimensions(t_boids *x, t_floatarg fdimen) +{ + size_t d = vec_dimensions_clamp((size_t)fdimen); + if (x->x_dimensions == d) + return; + boids_init(x, d, x->x_num_boids); +} + +static void boids_float(t_boids *x, t_floatarg fnum_boids) +{ + size_t num_boids = fnum_boids < 0.0 ? 0 : (size_t)fnum_boids; + if (x->x_num_boids == num_boids) + return; + boids_init(x, x->x_dimensions, num_boids); +} + +static void boids_mode(t_boids *x, t_floatarg f) +{ + const int m = (int)f; + x->x_mode = m < BOID_NEWPOS ? BOID_NEWPOS + : BOID_POSVEL < m ? BOID_POSVEL + : m; +} + +/* ----------------------- pd objects general initialization ---------------- */ + +static void boids_init_fields(t_boids *x, size_t dimensions) +{ + x->x_boid = NULL; + x->x_bounds = NULL; + x->x_params = NULL; + x->x_forces = NULL; + x->x_dimensions = vec_dimensions_clamp(dimensions); + x->x_num_boids = 0; + x->x_max_neighbors = 0; + x->x_mode = BOID_NEWPOS; + x->x_position_center.x = NULL; + x->x_position_center.x_dimensions = 0; + x->x_position_attract.x = NULL; + x->x_position_attract.x_dimensions = 0; +} + +static void *boids_donew(t_boids *x, t_floatarg f, t_floatarg g) +{ + x->x_out1 = outlet_new(&x->x_obj, gensym("list")); + x->x_out2 = outlet_new(&x->x_obj, gensym("list")); + boids_float(x, f ? f : 12.0); + boids_mode(x, g ? g : 0.0); + return x; +} + +static void *boids_new(t_floatarg f, t_floatarg g) +{ + t_boids *x = (t_boids *)pd_new(boids_class); + boids_init_fields(x, 2); + return boids_donew(x, f, g); +} + +static void *boids2d_new(t_floatarg f, t_floatarg g) +{ + t_boids *x = (t_boids *)pd_new(boids2d_class); + boids_init_fields(x, 2); + return boids_donew(x, f, g); +} + +static void *boids3d_new(t_floatarg f, t_floatarg g) +{ + t_boids *x = (t_boids *)pd_new(boids3d_class); + boids_init_fields(x, 3); + return boids_donew(x, f, g); +} + +void boids_setup(void) +{ + const char *boids_names[3] = {"boids2d", "boids3d", "boids"}; + t_newmethod boids_newfun[3] = {boids_newmethod_cast(boids2d_new), + boids_newmethod_cast(boids3d_new), + boids_newmethod_cast(boids_new)}; + t_class **boid_classes[3] = {&boids2d_class, &boids3d_class, &boids_class}; + + for (int i = 0; i < 3; ++i) + { + t_class *c = + class_new(gensym(boids_names[i]), boids_newfun[i], + (t_method)boids_free, sizeof(t_boids), 0, A_DEFFLOAT, + A_DEFFLOAT, A_NULL); + + *boid_classes[i] = c; + class_sethelpsymbol(c, gensym(boids_names[i])); + class_addfloat(c, (t_method)boids_float); + class_addbang(c, (t_method)boids_bang); + class_addmethod(c, (t_method)boids_num_neighbors, gensym("neighbors"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_float, gensym("number"), A_FLOAT, + A_NULL); + class_addmethod(c, (t_method)boids_mode, gensym("mode"), A_FLOAT, + A_NULL); + class_addmethod(c, (t_method)boids_minSpeed, gensym("minspeed"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_maxSpeed, gensym("maxspeed"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_centerWeight, gensym("center"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_attractWeight, gensym("attract"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_matchWeight, gensym("match"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_avoidWeight, gensym("avoid"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_wallsWeight, gensym("repel"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_edgeDist, gensym("edgedist"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_speedupFactor, gensym("speed"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_inertiaFactor, gensym("inertia"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_accelFactor, gensym("accel"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_prefDist, gensym("prefdist"), + A_FLOAT, A_NULL); + class_addmethod(c, (t_method)boids_bounds, gensym("flyrect"), A_GIMME, + A_NULL); + class_addmethod(c, (t_method)boids_position_attract, + gensym("attractpt"), A_GIMME, A_NULL); + class_addmethod(c, (t_method)boids_reset, gensym("reset"), A_NULL); + class_addmethod(c, (t_method)boids_reinit, gensym("init"), A_NULL); + class_addmethod(c, (t_method)boids_dump, gensym("dump"), A_NULL); + } + + class_addmethod(boids_class, (t_method)boids_dimensions, + gensym("dimensions"), A_FLOAT, A_NULL); + + logpost(NULL, 4, + "boids 2026 fdch / boids3d 2005-2006 a.sier / jasch © 1995-2003 " + "eric l. singer " + " " __DATE__ " " __TIME__); +} diff --git a/src/boids.h b/src/boids.h new file mode 100644 index 0000000..80b43ab --- /dev/null +++ b/src/boids.h @@ -0,0 +1,85 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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. +*/ +#ifndef BOIDS_H +#define BOIDS_H + +#include "boid_params.h" +#include "m_pd.h" +#include "vec.h" +#include + +#define kMaxLong 0xFFFFFFFF + +enum boid_output_mode +{ + BOID_NEWPOS = 0, + BOID_NEWOLD, + BOID_ALL, + BOID_POSVEL +}; + +typedef struct _neighbor t_neighbor; +typedef struct _boid t_boid; +typedef struct _boids t_boids; +typedef struct _boid_forces t_boid_forces; + +struct _neighbor +{ + t_neighbor *x_next; + t_boid *x_boid; + t_float x_distance; +}; + +struct _boid +{ + t_boid *x_next; + t_boids *x_flock; + t_neighbor *x_neighbors; + t_vec_state x_position; + t_vec_state x_direction; + t_float x_speed; +}; + +struct _boid_forces +{ + t_vec x_avoid_neighbors; + t_vec x_avoid_walls; + t_vec x_go_attract; + t_vec x_go_center; + t_vec x_match_neighbors; +}; + +struct _boids +{ + t_object x_obj; + t_outlet *x_out1; + t_outlet *x_out2; + + t_boid *x_boid; + t_float *x_bounds; + t_boid_params *x_params; + t_boid_forces *x_forces; + + t_vec x_position_center; + t_vec x_position_attract; + size_t x_dimensions; + size_t x_num_boids; + size_t x_max_neighbors; + enum boid_output_mode x_mode; +}; + +t_boid_forces *boid_forces_new(size_t dimensions); +void boid_forces_free(t_boid_forces *x); +void boid_forces_clear(t_boid_forces *x); +void boid_direction_update(t_vec_state *direction, t_boid_params *params, + t_boid_forces *forces); + +#endif diff --git a/src/vec.c b/src/vec.c new file mode 100644 index 0000000..afd268a --- /dev/null +++ b/src/vec.c @@ -0,0 +1,325 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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. +*/ +#include "vec.h" +#include "m_pd.h" +#include +#include +#include + +#define BOIDS_EPS ((t_float)1e-12) + +size_t vec_dimensions_clamp(size_t dimensions) +{ + return dimensions < 1 ? 1 : dimensions > 64 ? 64 : dimensions; +} + +t_float random_float_range(t_float min, t_float max) +{ + if (max < min) + { + t_float tmp = min; + min = max; + max = tmp; + } + + t_float u = (t_float)rand() / (t_float)RAND_MAX; + return min + u * (max - min); +} + +void vec_alloc(t_vec *x, size_t dimensions) +{ + if (!x) + return; + + size_t d = vec_dimensions_clamp(dimensions); + x->x_dimensions = d; + x->x = (t_float *)getbytes(sizeof(*x->x) * d); + vec_fill(x, 0.0); +} + +t_vec *vec_new(size_t dimensions) +{ + t_vec *x = (t_vec *)getbytes(sizeof(*x)); + if (!x) + return NULL; + + vec_alloc(x, dimensions); + return x; +} + +void vec_clear(t_vec *x) +{ + if (!x) + return; + + if (x->x) + freebytes(x->x, sizeof(*x->x) * x->x_dimensions); + + x->x = NULL; + x->x_dimensions = 0; +} + +void vec_free(t_vec *x) +{ + if (!x) + return; + + vec_clear(x); + freebytes(x, sizeof(*x)); +} + +void vec_fill(t_vec *x, t_float c) +{ + if (!x || !x->x) + return; + + if (c == 0.0) + { + memset(x->x, 0, sizeof(*x->x) * x->x_dimensions); + return; + } + + for (size_t i = 0; i < x->x_dimensions; ++i) + x->x[i] = c; +} + +void vec_copy(t_vec *dst, const t_vec *src) +{ + if (!dst || !src || dst->x_dimensions != src->x_dimensions) + return; + + memcpy(dst->x, src->x, sizeof(*dst->x) * dst->x_dimensions); +} + +void vec_update(t_vec *x, int argc, t_atom *argv) +{ + if (!x || !argv || argc != (int)x->x_dimensions) + return; + + for (int i = 0; i < argc; ++i) + x->x[i] = atom_getfloat(argv + i); +} + +void vec_random_range(t_vec *x, const t_float *range) +{ + if (!x || !range) + return; + + for (size_t i = 0; i < x->x_dimensions; ++i) + x->x[i] = random_float_range(range[i * 2], range[i * 2 + 1]); +} + +void vec_random_unit(t_vec *x) +{ + if (!x || !x->x_dimensions) + return; + + if (x->x_dimensions == 1) + { + x->x[0] = rand() & 1 ? 1.0 : -1.0; + return; + } + + if (x->x_dimensions == 2) + { + t_float angle = random_float_range(0.0, 360.0) * D2R; + x->x[0] = cos(angle); + x->x[1] = sin(angle); + return; + } + + /* Random point in a hypercube, normalized. Retry to avoid a zero vector. + */ + for (int tries = 0; tries < 8; ++tries) + { + for (size_t i = 0; i < x->x_dimensions; ++i) + x->x[i] = random_float_range(-1.0, 1.0); + + if (vec_normalize(x)) + return; + } + + vec_fill(x, 0.0); + x->x[0] = 1.0; +} + +void vec_add(t_vec *dst, const t_vec *src) +{ + if (!dst || !src || dst->x_dimensions != src->x_dimensions) + return; + + for (size_t i = 0; i < dst->x_dimensions; ++i) + dst->x[i] += src->x[i]; +} + +void vec_add_scaled(t_vec *dst, const t_vec *src, t_float scale) +{ + if (!dst || !src || dst->x_dimensions != src->x_dimensions) + return; + + for (size_t i = 0; i < dst->x_dimensions; ++i) + dst->x[i] += src->x[i] * scale; +} + +void vec_add_delta_unit_scaled(t_vec *dst, const t_vec *a, const t_vec *b, + t_float scale) +{ + if (!dst || !a || !b || dst->x_dimensions != a->x_dimensions || + a->x_dimensions != b->x_dimensions) + return; + + t_float len2 = 0.0; + for (size_t i = 0; i < a->x_dimensions; ++i) + { + t_float d = a->x[i] - b->x[i]; + len2 += d * d; + } + + if (len2 <= BOIDS_EPS) + return; + + t_float inv_len = 1.0 / sqrt(len2); + for (size_t i = 0; i < dst->x_dimensions; ++i) + dst->x[i] += (a->x[i] - b->x[i]) * inv_len * scale; +} + +void vec_scale(t_vec *x, t_float scale) +{ + if (!x) + return; + + for (size_t i = 0; i < x->x_dimensions; ++i) + x->x[i] *= scale; +} + +t_float vec_length_squared(const t_vec *x) +{ + if (!x) + return 0.0; + + t_float len2 = 0.0; + for (size_t i = 0; i < x->x_dimensions; ++i) + len2 += x->x[i] * x->x[i]; + return len2; +} + +t_float vec_length(const t_vec *x) +{ + return sqrt(vec_length_squared(x)); +} + +int vec_normalize(t_vec *x) +{ + t_float len = vec_length(x); + if (len <= BOIDS_EPS) + return 0; + + vec_scale(x, 1.0 / len); + return 1; +} + +void vec_average(t_vec *x, size_t count) +{ + if (!count) + return; + + vec_scale(x, 1.0 / (t_float)count); +} + +t_float vec_square_distance(const t_vec *a, const t_vec *b) +{ + if (!a || !b || a->x_dimensions != b->x_dimensions) + return 0.0; + + t_float distance = 0.0; + for (size_t i = 0; i < a->x_dimensions; ++i) + { + t_float d = a->x[i] - b->x[i]; + distance += d * d; + } + return distance; +} + +t_float vec_dot_offset_dir(const t_vec *a_pos, const t_vec *b_pos, + const t_vec *a_dir) +{ + if (!a_pos || !b_pos || !a_dir || + a_pos->x_dimensions != b_pos->x_dimensions || + a_pos->x_dimensions != a_dir->x_dimensions) + return 0.0; + + t_float dot = 0.0; + for (size_t i = 0; i < a_pos->x_dimensions; ++i) + dot += (b_pos->x[i] - a_pos->x[i]) * a_dir->x[i]; + return dot; +} + +void vec_state_alloc(t_vec_state *x, size_t dimensions) +{ + if (!x) + return; + + vec_alloc(&x->x_old, dimensions); + vec_alloc(&x->x_new, dimensions); +} + +void vec_state_clear(t_vec_state *x) +{ + if (!x) + return; + + vec_clear(&x->x_old); + vec_clear(&x->x_new); +} + +void vec_state_fill(t_vec_state *x, t_float c) +{ + if (!x) + return; + + vec_fill(&x->x_old, c); + vec_fill(&x->x_new, c); +} + +void vec_state_step(t_vec_state *x) +{ + if (!x) + return; + + vec_copy(&x->x_old, &x->x_new); +} + +void vec_state_update(t_vec_state *x, int argc, t_atom *argv) +{ + if (!x) + return; + + vec_state_step(x); + vec_update(&x->x_new, argc, argv); +} + +void vec_state_random_range(t_vec_state *x, const t_float *range) +{ + if (!x) + return; + + vec_random_range(&x->x_new, range); + vec_copy(&x->x_old, &x->x_new); +} + +void vec_state_random_unit(t_vec_state *x) +{ + if (!x) + return; + + vec_random_unit(&x->x_new); + vec_copy(&x->x_old, &x->x_new); +} diff --git a/src/vec.h b/src/vec.h new file mode 100644 index 0000000..bc667fa --- /dev/null +++ b/src/vec.h @@ -0,0 +1,77 @@ +/* + boids3d 2005 - 2006 a.sier / jasch + adapted from boids by eric singer © 1995-2003 eric l. singer + updated by fdch 2026 + + 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. +*/ +#ifndef VEC_H +#define VEC_H + +#include "m_pd.h" +#include + +#define BOIDS_PI \ + 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 +#define D2R (BOIDS_PI / 180.0) +#define R2D (180.0 / BOIDS_PI) + +/* + * This file is still named vec.* so existing build files do not have to + * change, but the type is now a plain vector. Old/new state belongs at the + * boid/state level, not inside every temporary vector. + */ + +typedef struct _vec +{ + size_t x_dimensions; + t_float *x; +} t_vec; + +typedef struct _vec_state +{ + t_vec x_old; + t_vec x_new; +} t_vec_state; + +size_t vec_dimensions_clamp(size_t dimensions); +t_float random_float_range(t_float min, t_float max); + +void vec_alloc(t_vec *x, size_t dimensions); +t_vec *vec_new(size_t dimensions); +void vec_clear(t_vec *x); +void vec_free(t_vec *x); +void vec_fill(t_vec *x, t_float c); +void vec_copy(t_vec *dst, const t_vec *src); +void vec_update(t_vec *x, int argc, t_atom *argv); +void vec_random_range(t_vec *x, const t_float *range); +void vec_random_unit(t_vec *x); + +void vec_add(t_vec *dst, const t_vec *src); +void vec_add_scaled(t_vec *dst, const t_vec *src, t_float scale); +void vec_add_delta_unit_scaled(t_vec *dst, const t_vec *a, const t_vec *b, + t_float scale); +void vec_scale(t_vec *x, t_float scale); +t_float vec_length_squared(const t_vec *x); +t_float vec_length(const t_vec *x); +int vec_normalize(t_vec *x); +void vec_average(t_vec *x, size_t count); +t_float vec_square_distance(const t_vec *a, const t_vec *b); +t_float vec_dot_offset_dir(const t_vec *a_pos, const t_vec *b_pos, + const t_vec *a_dir); + +void vec_state_alloc(t_vec_state *x, size_t dimensions); +void vec_state_clear(t_vec_state *x); +void vec_state_fill(t_vec_state *x, t_float c); +void vec_state_step(t_vec_state *x); +void vec_state_update(t_vec_state *x, int argc, t_atom *argv); +void vec_state_random_range(t_vec_state *x, const t_float *range); +void vec_state_random_unit(t_vec_state *x); + +/* Keep the old helper name around because boids.c and older callers used it. */ +#define max_dimensions vec_dimensions_clamp + +#endif diff --git a/tests/load-test.pd b/tests/load-test.pd new file mode 100644 index 0000000..b1ce273 --- /dev/null +++ b/tests/load-test.pd @@ -0,0 +1,28 @@ +#N canvas 0 0 530 402 12; +#X obj 37 37 boids2d; +#X obj 36 67 boids2d 5; +#X obj 35 95 boids2d 5 0; +#X obj 36 123 boids2d 5 1; +#X obj 35 149 boids2d 5 2; +#X obj 131 94 boids2d 15 0; +#X obj 131 148 boids2d 15 2; +#X obj 132 122 boids2d 15 1; +#X obj 137 64 boids2d 15; +#X obj 249 37 boids3d; +#X obj 248 67 boids3d 5; +#X obj 247 95 boids3d 5 0; +#X obj 248 123 boids3d 5 1; +#X obj 247 149 boids3d 5 2; +#X obj 349 64 boids3d 15; +#X obj 343 94 boids3d 15 0; +#X obj 344 122 boids3d 15 1; +#X obj 343 148 boids3d 15 2; +#X obj 43 207 boids; +#X obj 42 237 boids 5; +#X obj 41 265 boids 5 0; +#X obj 42 293 boids 5 1; +#X obj 41 319 boids 5 2; +#X obj 143 234 boids 15; +#X obj 137 264 boids 15 0; +#X obj 138 292 boids 15 1; +#X obj 137 318 boids 15 2;