diff --git a/organism/src/blur.cpp b/organism/src/blur.cpp new file mode 100644 index 0000000..e6f5f56 --- /dev/null +++ b/organism/src/blur.cpp @@ -0,0 +1,105 @@ +#include +#include "constants.h" +#include "config.h" +#include "util.h" + +void setupGaussianKernel(float* kernel, int width, float sigma) { + float sum = 0.0; + for(int i = 0; i < width; i++) { + //kernel[width+i] = exp( -(i*i) / (2 * sigma * sigma)) / (PI * 2 * sigma * sigma); + kernel[i] = exp(-0.5f * (i * i) / (sigma * sigma)); + sum += kernel[width]; + } + for(int i; i < width; i++) { + kernel[i] = sum/width; + } +} + +//float first_pass[PANEL_WIDTH][PANEL_HEIGHT]; +void gaussian_blur(float *field[PANEL_WIDTH][PANEL_HEIGHT]) { + float kernel[GAUSS_WIDTH]; + float first_pass[PANEL_WIDTH][PANEL_HEIGHT]; + memset(first_pass, 0.0, sizeof first_pass); + setupGaussianKernel(kernel, GAUSS_WIDTH, GAUSS_SIGMA); + // horizontal pass + for (int x = 0; x < PANEL_WIDTH; x++) { + for(int y = 0; y < PANEL_HEIGHT; y++) { + float sum = *field[x][y] * DECAY_FACTOR * kernel[0]; //0.0; + int additions = 1; + for (int x_offset = 1; x_offset < GAUSS_WIDTH; x_offset++) { + if (is_in_bounds(x+x_offset, y)) { + sum += *field[x + x_offset][y] * kernel[x_offset]; + additions++; + } + if (is_in_bounds(x-x_offset, y)) { + sum += *field[x - x_offset][y] * kernel[x_offset]; + additions++; + } + } + first_pass[x][y] = sum/GAUSS_WIDTH; + } + } + // vertical pass + for (int x = 0; x < PANEL_WIDTH; x++) { + for(int y = 0; y < PANEL_HEIGHT; y++) { + float sum = first_pass[x][y] * kernel[0]; //0.0; + int additions = 1; + for (int y_offset = 1; y_offset < GAUSS_WIDTH; y_offset++) { + if (is_in_bounds(x, y + y_offset)) { + sum += first_pass[x][y + y_offset] * kernel[y_offset]; + additions++; + } + if (is_in_bounds(x, y - y_offset)) { + sum += first_pass[x][y - y_offset] * kernel[y_offset]; + additions++; + } + } + *field[x][y] = sum/GAUSS_WIDTH; + } + } +} + +void box_blur(float field[PANEL_WIDTH][PANEL_HEIGHT]) { + auto first_pass = new float[PANEL_WIDTH][PANEL_HEIGHT](); + // horizontal pass + for (int x = 0; x < PANEL_WIDTH; x++) { + for(int y = 0; y < PANEL_HEIGHT; y++) { + float sum; + sum = field[x][y] * DECAY_FACTOR; //0.0; + int additions = 1; + for (int x_offset = 1; x_offset < BLUR_KERNEL_SIZE; x_offset++) { + if (is_in_bounds(x+x_offset, y)) { + sum += field[x + x_offset][y]; + additions++; + } + if (is_in_bounds(x-x_offset, y)) { + sum += field[x - x_offset][y]; + additions++; + } + } + first_pass[x][y] = (sum/additions); + } + } + // vertical pass + for (int x = 0; x < PANEL_WIDTH; x++) { + for(int y = 0; y < PANEL_HEIGHT; y++) { + float sum = first_pass[x][y]; //0.0; + int additions = 1; + for (int y_offset = 1; y_offset < BLUR_KERNEL_SIZE; y_offset++) { + if (is_in_bounds(x, y + y_offset)) { + sum += first_pass[x][y + y_offset]; + additions++; + } + if (is_in_bounds(x, y - y_offset)) { + sum += first_pass[x][y - y_offset]; + additions++; + } + } + + float result = (sum/additions); // * DECAY_FACTOR; + //attractant[x][y] = (((8.0*attractant[x][y]) + result) / 9.0); + field[x][y] = result; + } + } + delete[] first_pass; +} diff --git a/organism/src/blur.h b/organism/src/blur.h new file mode 100644 index 0000000..3ca9090 --- /dev/null +++ b/organism/src/blur.h @@ -0,0 +1,3 @@ +#include "constants.h" +void gaussian_blur(float *field[PANEL_WIDTH][PANEL_HEIGHT]); +void box_blur(float field[PANEL_WIDTH][PANEL_HEIGHT]); diff --git a/organism/src/config.h b/organism/src/config.h new file mode 100644 index 0000000..f9ad7f1 --- /dev/null +++ b/organism/src/config.h @@ -0,0 +1,18 @@ +// gaussian blur +#define GAUSS_WIDTH 1 +#define GAUSS_SIGMA 1.0 +#define DECAY_FACTOR 0.9 +// box blur +#define BLUR_KERNEL_SIZE 1 +// agent params +#define NUM_AGENTS_MIN 64 +#define NUM_AGENTS_MAX 301 +#define AGENT_DROP_AMOUNT 10 +#define AGENT_SENSOR_DISTANCE_MIN 2.0 +#define AGENT_SENSOR_DISTANCE_MAX 3.5 +// general params +#define NUM_ITERATIONS 500 +#define SPAWN_MIN_X 2 +#define SPAWN_MAX_X 63 +#define SPAWN_MIN_Y 2 +#define SPAWN_MAX_Y 31 diff --git a/organism/src/main.cpp b/organism/src/main.cpp index b6f6b15..a84dd08 100644 --- a/organism/src/main.cpp +++ b/organism/src/main.cpp @@ -4,7 +4,12 @@ #include "main.h" #include "constants.h" +#include "config.h" #include "overlay.h" +#include "util.h" + +#include "visual.h" +#include "blur.h" #include @@ -12,8 +17,8 @@ MatrixPanel_I2S_DMA *matrix = nullptr; -#define AGENT_DROP_AMOUNT 10 -#define NUM_ITERATIONS 500 +//#define AGENT_DROP_AMOUNT 10 +//#define NUM_ITERATIONS 500 struct SlimeAgent { int x_position; int y_position; @@ -63,33 +68,19 @@ void init_agents() { AGENT_SENSOR_ANGLE = 0.0875; } - //AGENT_SENSOR_DISTANCE = random(100, 400) / 1000.0; - //AGENT_SENSOR_DISTANCE = random(3000, 5000) / 1000.0; - AGENT_SENSOR_DISTANCE = random(2000, 3500) / 1000.0; - - NUM_AGENTS = random(64, 301); + AGENT_SENSOR_DISTANCE = random(AGENT_SENSOR_DISTANCE_MIN * 1000.0, AGENT_SENSOR_DISTANCE_MAX * 1000.0) / 1000.0; + NUM_AGENTS = random(NUM_AGENTS_MIN, NUM_AGENTS_MAX); agents.clear(); for(int a = 0; a < NUM_AGENTS; a++) { float angle = ((PI * 2) / NUM_AGENTS) * a; //agents[a].x_position = 31 + round(10*sin(angle)); //agents[a].y_position = 15 + round(10*cos(angle)); // agents[a].heading = ((PI * 2) / NUM_AGENTS) * ); - - //agents[a].x_position = random(12, 52); - //agents[a].y_position = random(12, 20); agents.push_back({ - random(2,63), - random(2,31), + random(SPAWN_MIN_X, SPAWN_MAX_X), + random(SPAWN_MIN_Y, SPAWN_MAX_Y), (random(0, 100) / 100.0) * (PI*2) }); - //agents.push_back({ - // random(6,58), - // random(4,28), - // (random(0, 100) / 100.0) * (PI*2) - //}); - //agents[a].x_position = random(0, 64); - //agents[a].y_position = random(0, 32); - //agents[a].heading = (random(0, 100) / 100.0) * (PI*2); } } @@ -124,166 +115,57 @@ void setup(){ init_attractant(); } -bool is_in_bounds(int x, int y) { - return (x < PANEL_WIDTH) and (y < PANEL_HEIGHT) and (x >= 0) and (y >= 0); -} +//void draw_bg() { +// int h_lines = round(PANEL_HEIGHT / 7); +// int v_lines = round(PANEL_WIDTH / 7); +// for(int v = 0; v <= v_lines; v++) { +// matrix->drawFastVLine(v*7+2, 0, PANEL_HEIGHT, matrix->color565(41, 17, 76)); +// } +// for(int h = 0; h <= h_lines; h++) { +// matrix->drawFastHLine(0, 7*h + 1, PANEL_WIDTH, matrix->color565(41, 17, 76)); +// } +//} +// +//void draw_attractant() { +// for(int x = 0; x 17.0) { +// matrix->drawPixel(x, y, matrix->color565( +// int((255.0 / 255.0) * round(attractant[x][y])), +// int((80.0 / 255.0) * round(attractant[x][y])), +// int((83.0 / 255.0) * round(attractant[x][y])) +// ) +// ); +// } +// } +// } +//} -void draw_bg() { - int h_lines = round(PANEL_HEIGHT / 7); - int v_lines = round(PANEL_WIDTH / 7); - for(int v = 0; v <= v_lines; v++) { - matrix->drawFastVLine(v*7+2, 0, PANEL_HEIGHT, matrix->color565(41, 17, 76)); - } - for(int h = 0; h <= h_lines; h++) { - matrix->drawFastHLine(0, 7*h + 1, PANEL_WIDTH, matrix->color565(41, 17, 76)); - } -} - -void draw_attractant() { - for(int x = 0; x 17.0) { - matrix->drawPixel(x, y, matrix->color565( - int((255.0 / 255.0) * round(attractant[x][y])), - int((80.0 / 255.0) * round(attractant[x][y])), - int((83.0 / 255.0) * round(attractant[x][y])) - ) - ); - } - } - } -} - -void setupGaussianKernel(float* kernel, int width, float sigma) { - float sum = 0.0; - for(int i = 0; i < width; i++) { - //kernel[width+i] = exp( -(i*i) / (2 * sigma * sigma)) / (PI * 2 * sigma * sigma); - kernel[i] = exp(-0.5f * (i * i) / (sigma * sigma)); - sum += kernel[width]; - } - for(int i; i < width; i++) { - kernel[i] = sum/width; - } -} - -#define GAUSS_WIDTH 1 -#define GAUSS_SIGMA 1.0 -#define DECAY_FACTOR 0.9 -float first_pass[PANEL_WIDTH][PANEL_HEIGHT]; -void gaussian_blur() { - float kernel[GAUSS_WIDTH]; - memset(first_pass, 0.0, sizeof first_pass); - setupGaussianKernel(kernel, GAUSS_WIDTH, GAUSS_SIGMA); - // horizontal pass - for (int x = 0; x < PANEL_WIDTH; x++) { - for(int y = 0; y < PANEL_HEIGHT; y++) { - float sum = attractant[x][y] * DECAY_FACTOR * kernel[0]; //0.0; - int additions = 1; - for (int x_offset = 1; x_offset < GAUSS_WIDTH; x_offset++) { - if (is_in_bounds(x+x_offset, y)) { - sum += attractant[x + x_offset][y] * kernel[x_offset]; - additions++; - } - if (is_in_bounds(x-x_offset, y)) { - sum += attractant[x - x_offset][y] * kernel[x_offset]; - additions++; - } - } - first_pass[x][y] = sum/GAUSS_WIDTH; - } - } - // vertical pass - for (int x = 0; x < PANEL_WIDTH; x++) { - for(int y = 0; y < PANEL_HEIGHT; y++) { - float sum = first_pass[x][y] * kernel[0]; //0.0; - int additions = 1; - for (int y_offset = 1; y_offset < GAUSS_WIDTH; y_offset++) { - if (is_in_bounds(x, y + y_offset)) { - sum += first_pass[x][y + y_offset] * kernel[y_offset]; - additions++; - } - if (is_in_bounds(x, y - y_offset)) { - sum += first_pass[x][y - y_offset] * kernel[y_offset]; - additions++; - } - } - attractant[x][y] = sum/GAUSS_WIDTH; - } - } -} - -#define BLUR_KERNEL_SIZE 1 -void box_blur() { - //Serial.println("memset: starting"); - memset(first_pass, 0.0, sizeof first_pass); - //Serial.println("memset: passed"); - // horizontal pass - for (int x = 0; x < PANEL_WIDTH; x++) { - for(int y = 0; y < PANEL_HEIGHT; y++) { - float sum; - sum = attractant[x][y] * DECAY_FACTOR; //0.0; - int additions = 1; - for (int x_offset = 1; x_offset < BLUR_KERNEL_SIZE; x_offset++) { - if (is_in_bounds(x+x_offset, y)) { - sum += attractant[x + x_offset][y]; - additions++; - } - if (is_in_bounds(x-x_offset, y)) { - sum += attractant[x - x_offset][y]; - additions++; - } - } - first_pass[x][y] = (sum/additions); - } - } - // vertical pass - for (int x = 0; x < PANEL_WIDTH; x++) { - for(int y = 0; y < PANEL_HEIGHT; y++) { - float sum = first_pass[x][y]; //0.0; - int additions = 1; - for (int y_offset = 1; y_offset < BLUR_KERNEL_SIZE; y_offset++) { - if (is_in_bounds(x, y + y_offset)) { - sum += first_pass[x][y + y_offset]; - additions++; - } - if (is_in_bounds(x, y - y_offset)) { - sum += first_pass[x][y - y_offset]; - additions++; - } - } - - float result = (sum/additions); // * DECAY_FACTOR; - //attractant[x][y] = (((8.0*attractant[x][y]) + result) / 9.0); - attractant[x][y] = result; - } - } -} - -int cleanup_x = 0; -void cleanup() { - int progress = iterations - NUM_ITERATIONS; - matrix->drawFastVLine(cleanup_x, 0, PANEL_HEIGHT, matrix->color565(254, 242, 255)); - if (cleanup_x > 0) { - matrix->fillRect(0, 0, cleanup_x, PANEL_HEIGHT, matrix->color565(16, 0, 16)); - } - int h_lines = round(PANEL_HEIGHT / 7); - int v_lines = round(cleanup_x / 7); - for(int v = 0; v < cleanup_x; v++) { - if (v%7 == 2) { - matrix->drawFastVLine(v, 0, PANEL_HEIGHT, matrix->color565(41, 17, 76)); - } - } - for(int h = 0; h <= h_lines; h++) { - matrix->drawFastHLine(0, 7*h + 1, cleanup_x-1, matrix->color565(41, 17, 76)); - } - cleanup_x++; - if (cleanup_x > PANEL_WIDTH) { - iterations = 0; - cleanup_x = 0; - init_attractant(); - init_agents(); - } -} +//int cleanup_x = 0; +//void cleanup() { +// int progress = iterations - NUM_ITERATIONS; +// matrix->drawFastVLine(cleanup_x, 0, PANEL_HEIGHT, matrix->color565(254, 242, 255)); +// if (cleanup_x > 0) { +// matrix->fillRect(0, 0, cleanup_x, PANEL_HEIGHT, matrix->color565(16, 0, 16)); +// } +// int h_lines = round(PANEL_HEIGHT / 7); +// int v_lines = round(cleanup_x / 7); +// for(int v = 0; v < cleanup_x; v++) { +// if (v%7 == 2) { +// matrix->drawFastVLine(v, 0, PANEL_HEIGHT, matrix->color565(41, 17, 76)); +// } +// } +// for(int h = 0; h <= h_lines; h++) { +// matrix->drawFastHLine(0, 7*h + 1, cleanup_x-1, matrix->color565(41, 17, 76)); +// } +// cleanup_x++; +// if (cleanup_x > PANEL_WIDTH) { +// iterations = 0; +// cleanup_x = 0; +// init_attractant(); +// init_agents(); +// } +//} void loop() { matrix ->flipDMABuffer(); @@ -291,8 +173,8 @@ void loop() { matrix->fillScreenRGB888(15, 0, 10); // draw background and organism - draw_bg(); - draw_attractant(); + draw_bg(matrix); + draw_attractant(matrix, attractant); for(int a = 0; a < NUM_AGENTS; a++) { //matrix->drawPixel(agents[a].x_position, agents[a].y_position, matrix->color565(0, 0, attractant[agents[a].x_position][agents[a].y_position])); @@ -336,12 +218,16 @@ void loop() { } iterations++; if (iterations % 2 == 0) { //64 && iterations % 64 == 0) { // (( == 0) { - box_blur(); + box_blur(attractant); //gaussian_blur(); ; } if (iterations >= NUM_ITERATIONS) { - cleanup(); + //cleanup(); + if (cleanup(matrix, &iterations)) { + init_attractant(); + init_agents(); + } } } diff --git a/organism/src/util.cpp b/organism/src/util.cpp new file mode 100644 index 0000000..e445ef5 --- /dev/null +++ b/organism/src/util.cpp @@ -0,0 +1,5 @@ +#include "constants.h" + +bool is_in_bounds(int x, int y) { + return (x < PANEL_WIDTH) and (y < PANEL_HEIGHT) and (x >= 0) and (y >= 0); +} diff --git a/organism/src/util.h b/organism/src/util.h new file mode 100644 index 0000000..3289174 --- /dev/null +++ b/organism/src/util.h @@ -0,0 +1,2 @@ +bool is_in_bounds(int x, int y); + diff --git a/organism/src/visual.cpp b/organism/src/visual.cpp new file mode 100644 index 0000000..9a96ed4 --- /dev/null +++ b/organism/src/visual.cpp @@ -0,0 +1,54 @@ +#include "constants.h" +#include "visual.h" + +void draw_bg(MatrixPanel_I2S_DMA *matrix) { + int h_lines = round(PANEL_HEIGHT / 7); + int v_lines = round(PANEL_WIDTH / 7); + for(int v = 0; v <= v_lines; v++) { + matrix->drawFastVLine(v*7+2, 0, PANEL_HEIGHT, matrix->color565(41, 17, 76)); + } + for(int h = 0; h <= h_lines; h++) { + matrix->drawFastHLine(0, 7*h + 1, PANEL_WIDTH, matrix->color565(41, 17, 76)); + } +} + +void draw_attractant(MatrixPanel_I2S_DMA *matrix, float attractant[PANEL_WIDTH][PANEL_HEIGHT]) { + for(int x = 0; x 17.0) { + matrix->drawPixel(x, y, matrix->color565( + int((255.0 / 255.0) * round(attractant[x][y])), + int((80.0 / 255.0) * round(attractant[x][y])), + int((83.0 / 255.0) * round(attractant[x][y])) + ) + ); + } + } + } +} + +int cleanup_x = 0; +bool cleanup(MatrixPanel_I2S_DMA *matrix, int* iterations) { + int progress = *iterations - NUM_ITERATIONS; + matrix->drawFastVLine(cleanup_x, 0, PANEL_HEIGHT, matrix->color565(254, 242, 255)); + if (cleanup_x > 0) { + matrix->fillRect(0, 0, cleanup_x, PANEL_HEIGHT, matrix->color565(16, 0, 16)); + } + int h_lines = round(PANEL_HEIGHT / 7); + int v_lines = round(cleanup_x / 7); + for(int v = 0; v < cleanup_x; v++) { + if (v%7 == 2) { + matrix->drawFastVLine(v, 0, PANEL_HEIGHT, matrix->color565(41, 17, 76)); + } + } + for(int h = 0; h <= h_lines; h++) { + matrix->drawFastHLine(0, 7*h + 1, cleanup_x-1, matrix->color565(41, 17, 76)); + } + cleanup_x++; + if (cleanup_x > PANEL_WIDTH) { + *iterations = 0; + cleanup_x = 0; + return true; + } + return false; +} diff --git a/organism/src/visual.h b/organism/src/visual.h new file mode 100644 index 0000000..04659d1 --- /dev/null +++ b/organism/src/visual.h @@ -0,0 +1,6 @@ +#include +#include "constants.h" +#include "config.h" +void draw_bg(MatrixPanel_I2S_DMA *matrix); +void draw_attractant(MatrixPanel_I2S_DMA *matrix, float attractant[PANEL_WIDTH][PANEL_HEIGHT]); +bool cleanup(MatrixPanel_I2S_DMA *matrix, int* iterations);