Skip to content

Instantly share code, notes, and snippets.

@hpwit
Created March 14, 2023 07:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hpwit/0cf4d0d6fe5f4e218c11e9a6535d3aa0 to your computer and use it in GitHub Desktop.
Save hpwit/0cf4d0d6fe5f4e218c11e9a6535d3aa0 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include "WiFi.h"
#define ARTNET_STAT
#include "artnetESP32V2.h"
//#define ESP_VIRTUAL_DRIVER_8 1 //to use the 8:1 ratio
#define HARDWARESPRITES 0
#define ALTERNATEPATTERN 1
#define STATICCOLOR 0 //to get
//#define FULL_DMA_BUFFER
#define NBIS2SERIALPINS 2 //number of esp32 pins you will use. the total number of strips available will be NBIS2SERIALPINS * 8 here 72 strips
#define NUM_LEDS_PER_STRIP (123*3)//the length of your strip if you have different strips size put here the longuest strip
//#define MULTIPLE_LEDSBUFFER //use the mode several leds buffers in that mode the number of NBIS2SERIALPINS has to be <=12
#define STATIC_COLOR_GRB 1
#define USE_FASTLED //te enable the needed types
//#define YVESPANEL
#define STATICCOLOR 0
#define USE_FASTLED
#define COLOR_GRB
#define __HARDWARE_MAP
#include "pixelslib.h"
#include "I2SClocklessVirtualLedDriver.h"
#include "Arduino.h"
#define LATCH_PIN 4
#define CLOCK_PIN 26 //for a reason I don't know, the CLOCK_PIN needs to be >=16
#define LED_WIDTH 123
#define LED_HEIGHT 48
#define NUM_STRIPS NBIS2SERIALPINS * 8
#define NUM_LEDS NUM_LEDS_PER_STRIP *NUM_STRIPS
CRGB Color=CRGB::Green;
typedef struct pixelrender{
uint8_t bl;
uint8_t tl;
uint8_t tr;
uint8_t br;
} pixelrender;
uint16_t XY(uint8_t x, uint8_t y) {
//if (y & 1)
//return (y + 1) * WIDTH - 1 - x;
//else
return y * LED_WIDTH + x;
}
float c, d, e, f, _time; // some _timedependant counters
// the actual polar coordinates
int x, y; // the cartesian coordiantes
int num_x = LED_WIDTH; // horizontal pixel count
int num_y = LED_HEIGHT; // vertical pixel count
int _CENTER_X,_CENTER_Y;
// Background for setting the following 2 numbers: the FastLED inoise16() function returns
// raw values ranging from 0-65535. In order to improve contrast we filter this output and
// stretch the remains. In histogram (photography) terms this means setting a blackpoint and
// a whitepoint. low_limit MUST be smaller than high_limit.
const uint16_t low_limit = 30000; // everything lower drawns in black
// higher numer = more black & more contrast present
const uint16_t high_limit = 50000; // everything higher gets maximum brightness & bleeds out
// lower number = the result will be more bright & shiny
float center_x = (num_x / 2) - 0.5; // the reference point for polar coordinates
float center_y = (num_y / 2) - 0.5; // (can also be outside of the actual xy matrix)
float rnd;
float spd;
int lengths[16]={369,369,369,369,369,369,369,369,369,369,369,369,369,369,369,369};
int Pins[15] = {12, 32,25,26,27,0,2};
//these two lines do more or less the same thing the second one enable double buffer for fastled hence faster even when using only one core for display
//CRGB leds[123*48];
frameBuffer leds=frameBuffer(NUM_STRIPS * NUM_LEDS_PER_STRIP);
OffsetDisplay offd;
I2SClocklessVirtualLedDriver driver;
// artnetESP32V2 udp=artnetESP32V2();
//this is the mapping function of my panel here really simple
uint16_t mapfunction(uint16_t pos)
{
int x= pos%LED_WIDTH;
int y= pos/LED_WIDTH;
if(y%2==0)
{
return y*LED_WIDTH+x;
}
else
{
return y*LED_WIDTH+LED_WIDTH-x-1;
}
// return Y*16*8+X;
}
float theta[LED_WIDTH][LED_HEIGHT];
float distance[LED_WIDTH][LED_HEIGHT];
float newdistance[LED_WIDTH][LED_HEIGHT];
float linear_c; // some linear rising offsets
float linear_d ;
float linear_e ;
float angle_c ; // some angle offsets
float angle_d ;
float angle_e;
long t1;
static TaskHandle_t FastLEDshowTaskHandle = 0;
static TaskHandle_t FastLEDshowTaskHandle2 = 0;
struct pixelrender render_pixel2(float _newdist,float _newangle,float _scale_x,float _scale_y,float _offset_x,float _offset_y,float _z) {
// convert polar coordinates back to cartesian ones
//fmodf(newangle, 2 * PI); //NO, not here!
pixelrender results;
float c= cosf(_newangle) * _newdist;
float s= sinf(_newangle) * _newdist;
float newx = (_offset_x + center_x - c) * _scale_x;
float newy = (_offset_y + center_y - s) * _scale_y;
// render noisevalue at this new cartesian point
uint16_t raw_noise_field_value = inoise16(newx, newy, _z);
//uint16_t raw_noise_field_value=(low_limit+high_limit)/2;
// a lot is happening here, namely
// A) enhance histogram (improve contrast) by setting the black and white point
// B) scale the result to a 0-255 range
// it's the contrast boosting & the "colormapping" (technically brightness mapping)
if (raw_noise_field_value < low_limit) raw_noise_field_value = low_limit;
if (raw_noise_field_value > high_limit) raw_noise_field_value = high_limit;
results.bl = map(raw_noise_field_value, low_limit, high_limit, 0, 255);
newx = (_offset_x + center_x + c) * _scale_x;
newy = (_offset_y + center_y + s) * _scale_y;
// render noisevalue at this new cartesian point
raw_noise_field_value = inoise16(newx, newy, _z);
//uint16_t raw_noise_field_value=(low_limit+high_limit)/2;
// a lot is happening here, namely
// A) enhance histogram (improve contrast) by setting the black and white point
// B) scale the result to a 0-255 range
// it's the contrast boosting & the "colormapping" (technically brightness mapping)
if (raw_noise_field_value < low_limit) raw_noise_field_value = low_limit;
if (raw_noise_field_value > high_limit) raw_noise_field_value = high_limit;
results.tl = map(raw_noise_field_value, low_limit, high_limit, 0, 255);
return results;
// done, we've just rendered one color value for one single pixel
}
void task1(void *pvParameters)
{
float newdist, newangle ,newangletl,newangletr,newanglebr; // parameters for reconstruction
float z; // 3d dimension for the 3d noise function
float offset_x, offset_y; // wanna shift the cartesians during run_time?
float scale_x, scale_y; // cartesian scaling in 2 dimensions
float dist, angle;
for(;;)
{
ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
for (int y = 12; y < _CENTER_Y; y++){
for (int x = 0; x < _CENTER_X; x++) {
// pick data from look up table (helps the framerate on slow processors ;)
dist = distance [x] [y];
angle = theta [x] [y];
newdist = newdistance [x] [y];
scale_x = 15000;
scale_y = 15000;
newangle= angle + angle_c - (dist * 0.2); //bottom left
newangletl=-angle + angle_c - (dist * 0.2);
//newangletr=PI+angle + angle_c - (dist * 0.2);
//newanglebr=-(PI+angle) + angle_c - (dist * 0.2);
// newangle0 = angle + angle_c - (dist * 0.2);
// newdist = sqrtf(dist);
z = 500000000 - (( dist / 6 ) - linear_c) * 100000;
offset_x = 0;
offset_y = 0;
// convert polar coordinates back to cartesian
// & render noise value there
pixelrender r= render_pixel2(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
pixelrender r2= render_pixel2(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show1=r.bl;
uint8_t show1tl=r2.bl;
uint8_t show1tr=r.tl;
uint8_t show1br=r2.tl;
//uint8_t show1 = render_pixel(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
//uint8_t show1tl = render_pixel(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
//uint8_t show1tr = render_pixel(newdist,newangletr,scale_x,scale_y,offset_x,offset_y,z) ;
//uint8_t show1br = render_pixel(newdist,newanglebr,scale_x,scale_y,offset_x,offset_y,z) ;
// *ledp= render_pixel(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
// ledp++;
// Layer 2 - green -------------------------------------------------------
scale_x = 14000;
scale_y = 14000;
newangle = angle + angle_d - (dist * 0.23);
newangletl=-angle + angle_d - (dist * 0.23);
// newangletr=PI+angle + angle_d - (dist * 0.23);
//newanglebr=-(PI+angle) + angle_d - (dist * 0.23);
z = 500000000 - (( dist / 5 ) - linear_d) * 110000;
offset_x = 42;
offset_y = 69;
r= render_pixel2(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
r2= render_pixel2(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show2=r.bl;
uint8_t show2tl=r2.bl;
uint8_t show2tr=r.tl;
uint8_t show2br=r2.tl;
/*
uint8_t show2 = render_pixel(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show2tl = render_pixel(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show2tr = render_pixel(newdist,newangletr,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show2br = render_pixel(newdist,newanglebr,scale_x,scale_y,offset_x,offset_y,z) ;
*/
// *ledp= render_pixel(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
//ledp++;
// Layer 3 - blue -------------------------------------------------------
scale_x = 13000;
scale_y = 13000;
newangle = angle + angle_e - (dist * 0.19);
newangletl=-angle + angle_e - (dist * 0.19);
// newangletr=PI+angle + angle_e - (dist * 0.19);
// newanglebr=-(PI+angle) + angle_e - (dist * 0.19);
z = 500000000 - (( dist / 4 ) - linear_e) * 120000;
offset_x = 420;
offset_y = 690;
r= render_pixel2(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
r2= render_pixel2(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show3=r.bl;
uint8_t show3tl=r2.bl;
uint8_t show3tr=r.tl;
uint8_t show3br=r2.tl;
/*
uint8_t show3 = render_pixel(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show3tl = render_pixel(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show3tr = render_pixel(newdist,newangletr,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show3br = render_pixel(newdist,newanglebr,scale_x,scale_y,offset_x,offset_y,z) ;
*/
// *ledp= render_pixel(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
// ledp++;
// assign the rendered values to colors (aka colormapping)
CRGB color = CRGB(show1,show2, show3);
CRGB colortl = CRGB(show1tl,show2tl, show3tl);
CRGB colortr = CRGB(show1tr,show2tr, show3tr);
CRGB colorbr = CRGB(show1br,show2br, show3br);
// CRGB color = CRGB(show1, show2, 0);
// write the rendered pixel into the framebutter
leds[XY(x, y)] = color;
leds[XY(x, y+2*(_CENTER_Y-y)-1)] = colortl; //les Y
leds[XY(x+2*(_CENTER_X-x)-1, y+2*(_CENTER_Y-y)-1)] = colortr;
leds[XY(x+2*(_CENTER_X-x)-1, y)] = colorbr;
}
}
}
}
long timer()
{
return ESP.getCycleCount()/240000-t1;
}
void setup()
{
Serial.begin(2000000);
render_lookup_table();
xTaskCreatePinnedToCore(task1, "FastLEDshowTask", 2048, NULL,2, &FastLEDshowTaskHandle, 0);
driver.setMapLed(&mapfunction); //creatie the mapping table in memory to be called by the led driver itself
// driver.initled((uint8_t *)leds, Pins, CLOCK_PIN, LATCH_PIN);
driver.initled(&leds, Pins, CLOCK_PIN, LATCH_PIN);
driver.setBrightness(32);
//
//setTableBrightness(40);
//driver.setGamma(0.4,0.6,0.6);
//not all my strips are of the same batch and some of them are RGRB and RGB ... stupiod of me
driver.setColorOrderPerStrip(0,ORDER_GRB);
driver.setColorOrderPerStrip(1,ORDER_GRB);
driver.setColorOrderPerStrip(2,ORDER_GRB);
driver.setColorOrderPerStrip(3,ORDER_GRB);
driver.setColorOrderPerStrip(4,ORDER_GRB);
driver.setColorOrderPerStrip(5,ORDER_GRB);
driver.setColorOrderPerStrip(6,ORDER_GRB);
driver.setColorOrderPerStrip(7,ORDER_GRB);
driver.setColorOrderPerStrip(8,ORDER_RGB);
driver.setColorOrderPerStrip(9,ORDER_RGB);
driver.setColorOrderPerStrip(10,ORDER_RGB);
driver.setColorOrderPerStrip(11,ORDER_RGB);
driver.setColorOrderPerStrip(12,ORDER_RGB);
driver.setColorOrderPerStrip(13,ORDER_RGB);
driver.setColorOrderPerStrip(14,ORDER_RGB);
driver.setColorOrderPerStrip(15,ORDER_RGB);
spd = 600; // global speed for everything. Higher number = slower animation
if(LED_WIDTH%2==0)
{
_CENTER_X=LED_WIDTH/2;
}
else
{
_CENTER_X=LED_WIDTH/2+1;
}
if(LED_HEIGHT%2==0)
{
_CENTER_Y=LED_HEIGHT/2;
}
else
{
_CENTER_Y=LED_HEIGHT/2+1;
}
randomSeed(analogRead(13));
rnd = random(1000000); // just a different starting point for each program start
}
uint8_t * ledp;
float * _dist=(float *)distance;
float * _angle=(float *)theta;
float * _newdi=(float *)newdistance;
void loop() {
// set timers
float newdist, newangle ,newangletl,newangletr,newanglebr; // parameters for reconstruction
float z; // 3d dimension for the 3d noise function
float offset_x, offset_y; // wanna shift the cartesians during run_time?
float scale_x, scale_y; // cartesian scaling in 2 dimensions
float dist, angle;
_time = millis(); // save elapsed ms since start up
_time = _time * 0.6 ; // global anaimation speed
linear_c = _time * 0.0025; // some linear rising offsets
linear_d = _time * 0.0030;
linear_e = _time * 0.0023;
angle_c = fmodf(linear_c, 2 * PI);; // some angle offsets
angle_d = fmodf(linear_d, 2 * PI);;
angle_e = fmodf(linear_e, 2 * PI);;
// the HOT LOOP where the magic happens
long time2=ESP.getCycleCount();
xTaskNotifyGive(FastLEDshowTaskHandle);
for (int y = 0; y < 12; y++){
for (int x = 0; x < _CENTER_X; x++) {
// pick data from look up table (helps the framerate on slow processors ;)
dist = distance [x] [y];
angle = theta [x] [y];
newdist = newdistance [x] [y];
// layer 1: RED-------------------------------------------------------------
// calculate distance and angle of the point relative to
// the origin described by center_x & center_y
// get_polar_values();
// set all parameters for the first layer (red)
scale_x = 15000;
scale_y = 15000;
newangle= angle + angle_c - (dist * 0.2); //bottom left
newangletl=-angle + angle_c - (dist * 0.2);
//newangletr=PI+angle + angle_c - (dist * 0.2);
//newanglebr=-(PI+angle) + angle_c - (dist * 0.2);
// newangle0 = angle + angle_c - (dist * 0.2);
// newdist = sqrtf(dist);
z = 500000000 - (( dist / 6 ) - linear_c) * 100000;
offset_x = 0;
offset_y = 0;
// convert polar coordinates back to cartesian
// & render noise value there
pixelrender r= render_pixel2(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
pixelrender r2= render_pixel2(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show1=r.bl;
uint8_t show1tl=r2.bl;
uint8_t show1tr=r.tl;
uint8_t show1br=r2.tl;
//uint8_t show1 = render_pixel(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
//uint8_t show1tl = render_pixel(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
//uint8_t show1tr = render_pixel(newdist,newangletr,scale_x,scale_y,offset_x,offset_y,z) ;
//uint8_t show1br = render_pixel(newdist,newanglebr,scale_x,scale_y,offset_x,offset_y,z) ;
// *ledp= render_pixel(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
// ledp++;
// Layer 2 - green -------------------------------------------------------
scale_x = 14000;
scale_y = 14000;
newangle = angle + angle_d - (dist * 0.23);
newangletl=-angle + angle_d - (dist * 0.23);
// newangletr=PI+angle + angle_d - (dist * 0.23);
//newanglebr=-(PI+angle) + angle_d - (dist * 0.23);
z = 500000000 - (( dist / 5 ) - linear_d) * 110000;
offset_x = 42;
offset_y = 69;
r= render_pixel2(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
r2= render_pixel2(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show2=r.bl;
uint8_t show2tl=r2.bl;
uint8_t show2tr=r.tl;
uint8_t show2br=r2.tl;
// Layer 3 - blue -------------------------------------------------------
scale_x = 13000;
scale_y = 13000;
newangle = angle + angle_e - (dist * 0.19);
newangletl=-angle + angle_e - (dist * 0.19);
// newangletr=PI+angle + angle_e - (dist * 0.19);
// newanglebr=-(PI+angle) + angle_e - (dist * 0.19);
z = 500000000 - (( dist / 4 ) - linear_e) * 120000;
offset_x = 420;
offset_y = 690;
r= render_pixel2(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
r2= render_pixel2(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show3=r.bl;
uint8_t show3tl=r2.bl;
uint8_t show3tr=r.tl;
uint8_t show3br=r2.tl;
/*
uint8_t show3 = render_pixel(newdist,newangle,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show3tl = render_pixel(newdist,newangletl,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show3tr = render_pixel(newdist,newangletr,scale_x,scale_y,offset_x,offset_y,z) ;
uint8_t show3br = render_pixel(newdist,newanglebr,scale_x,scale_y,offset_x,offset_y,z) ;
*/
// assign the rendered values to colors (aka colormapping)
CRGB color = CRGB(show1,show2, show3);
CRGB colortl = CRGB(show1tl,show2tl, show3tl);
CRGB colortr = CRGB(show1tr,show2tr, show3tr);
CRGB colorbr = CRGB(show1br,show2br, show3br);
// CRGB color = CRGB(show1, show2, 0);
// write the rendered pixel into the framebutter
leds[XY(x, y)] = color;
leds[XY(x, y+2*(_CENTER_Y-y)-1)] = colortl; //les Y
leds[XY(x+2*(_CENTER_X-x)-1, y+2*(_CENTER_Y-y)-1)] = colortr;
leds[XY(x+2*(_CENTER_X-x)-1, y)] = colorbr;
}
}
// make the frame appear nice to humans (the eye has no linear brightness sensitivity)
// adjust_gamma();
// BRING IT ON! SHOW WHAT YOU GOT!
long time4=ESP.getCycleCount();
driver.showPixels();
long time3=ESP.getCycleCount();
Serial.printf("Calculations showPixels %0.2fps fps:%.2f \n",(float)240000000/(time4-time2),(float)240000000/(time3-time2));
// check serial monito for current fps
//EVERY_N_MILLIS(500) Serial.println(FastLED.getFPS());
}
// calculate distance and angle of the point relative to
// the polar origin defined by center_x & center_y
void get_polar_values() {
// calculate current cartesian distances (deltas) from polar origin point
float dx = x - center_x;
float dy = y - center_y;
// calculate distance between current point & polar origin
// (length of the origin vector, pythgorean theroem)
// dist = sqrt((dx*dx)+(dy*dy));
float dist = hypotf(dx, dy);
// calculate the angle
// (where around the polar origin is the current point?)
float angle = atan2f(dy, dx);
// done, that's all we need
}
// convert polar coordinates back to cartesian
// & render noise value there
uint8_t render_pixel(float _newdist,float _newangle,float _scale_x,float _scale_y,float _offset_x,float _offset_y,float _z) {
// convert polar coordinates back to cartesian ones
//fmodf(newangle, 2 * PI); //NO, not here!
float newx = (_offset_x + center_x - (cosf(_newangle) * _newdist)) * _scale_x;
float newy = (_offset_y + center_y - (sinf(_newangle) * _newdist)) * _scale_y;
// render noisevalue at this new cartesian point
uint16_t raw_noise_field_value = inoise16(newx, newy, _z);
//uint16_t raw_noise_field_value=(low_limit+high_limit)/2;
// a lot is happening here, namely
// A) enhance histogram (improve contrast) by setting the black and white point
// B) scale the result to a 0-255 range
// it's the contrast boosting & the "colormapping" (technically brightness mapping)
if (raw_noise_field_value < low_limit) raw_noise_field_value = low_limit;
if (raw_noise_field_value > high_limit) raw_noise_field_value = high_limit;
uint8_t scaled_noise_value = map(raw_noise_field_value, low_limit, high_limit, 0, 255);
return scaled_noise_value;
// done, we've just rendered one color value for one single pixel
}
// find the right led index in a serpentine matrix
/*
// alternative for row by row matrix setup
uint16_t XY(uint8_t x, uint8_t y) {
return y * WIDTH + x;
}
*/
// make it look nicer - expand low brightness values and compress high brightness values,
// basically we perform gamma curve bending for all 3 color chanels,
// making more detail visible which otherwise tends to get lost in brightness
void adjust_gamma()
{
for (uint16_t i = 0; i < NUM_LEDS; i++)
{
leds[i].r = dim8_video(leds[i].r);
leds[i].g = dim8_video(leds[i].g);
leds[i].b = dim8_video(leds[i].b);
}
}
void render_lookup_table() {
center_x = (num_x / 2) - 0.5;
center_y = (num_y / 2) - 0.5;
for (int xx = 0; xx < num_x; xx++) {
for (int yy = 0; yy < num_y; yy++) {
float dx = xx - center_x;
float dy = yy - center_y;
distance[xx] [yy] = hypotf(dx, dy);
theta[xx] [yy] = atan2f(dy, dx);
newdistance[xx][yy]=sqrtf( distance[xx] [yy] );
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment