Skip to content

Commit

Permalink
Add trigo struct, support pan, tilt, roll, add 6Rings and SpaceStation
Browse files Browse the repository at this point in the history
app.js: correct rotation using PI
index.js: bugfix

LedFixture.cpp: tune Distance (from centre) for 2D , use trigo

LedLeds.h: add Trigo struct

LedModFixture
- rename mHead var to viewRot
- add viewRotatation variable
- support pan (WIP)

LedModFixtureGen
- refactor write3D
- ring and ring241: use middle instead of first and calculate pixel and support rotation
- cone and globe and human: use ring (tilt 90)
- wall: use middle coordinates for rings
- add 6Rings and SpaceStation

SysModModel: Coord3D
- use int instead of unsigned16 (WIP)
- operator-:  allow negative
  • Loading branch information
ewowi committed Mar 22, 2024
1 parent d43aff0 commit 826a417
Show file tree
Hide file tree
Showing 10 changed files with 1,656 additions and 1,528 deletions.
6 changes: 3 additions & 3 deletions data/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,9 @@ function preview3D(canvasNode, buffer) {

// controls.rotateSpeed = 0.4;
//moving heads rotation
scene.rotation.x = buffer[1];
scene.rotation.y = buffer[2];
scene.rotation.z = buffer[3];
scene.rotation.x = buffer[1] / 255 * Math.PI * 2;
scene.rotation.y = buffer[2] / 255 * Math.PI * 2;
scene.rotation.z = buffer[3] / 255 * Math.PI * 2;

controls.update(); // apply orbit controls

Expand Down
5 changes: 3 additions & 2 deletions data/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ function receiveData(json) {
else if (key == "addRow") { //update the row of a table
console.log("receiveData", key, value);

if (value.id && value.rowNr) {
if (value.id && value.rowNr != null) {
let tableId = value.id;
let rowNr = value.rowNr;

Expand All @@ -600,7 +600,8 @@ function receiveData(json) {

genTableRowHTML(tableVar, tableNode, newRowNr);
}
else console.log("dev receiveData addRow no id and/or rowNr specified", key, value);
else
console.log("dev receiveData addRow no id and/or rowNr specified", key, value);

} else if (key == "delRow") { //update the row of a table

Expand Down
1 change: 1 addition & 0 deletions src/App/LedEffects.h
Original file line number Diff line number Diff line change
Expand Up @@ -1622,6 +1622,7 @@ class Effects {
// effect->loop(leds); //do a loop to set sharedData right
// leds.sharedData.loop();
leds.doMap = true; // avoid effects loop to set contextRowNr
delay(100); // give looptask the time to stop the effect tbd: this is a bit of a hack
mdl->varPreDetails(var, rowNr);
effect->controls(var);
mdl->varPostDetails(var, rowNr);
Expand Down
51 changes: 27 additions & 24 deletions src/App/LedFixture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ void Fixture::projectAndMap() {
unsigned16 currPin; //lookFor needs u16

//what to deserialize
starModJson.lookFor("width", &size.x);
starModJson.lookFor("height", &size.y);
starModJson.lookFor("depth", &size.z);
starModJson.lookFor("width", (unsigned16 *)&size.x);
starModJson.lookFor("height", (unsigned16 *)&size.y);
starModJson.lookFor("depth", (unsigned16 *)&size.z);
starModJson.lookFor("nrOfLeds", &nrOfLeds);
starModJson.lookFor("pin", &currPin);

Expand Down Expand Up @@ -252,6 +252,7 @@ void Fixture::projectAndMap() {
USER_PRINTF("dev pre [%d] indexV too high %d>=%d or %d (m:%d p:%d) p:%d,%d,%d s:%d,%d,%d\n", rowNr, indexV, leds->nrOfLeds, NUM_LEDS_Max, leds->mappingTable.size(), indexP, pixel.x, pixel.y, pixel.z, leds->size.x, leds->size.y, leds->size.z);
}
else {
Trigo trigo(trigoInt8);
//post processing:
switch(leds->projectionNr) {
case p_DistanceFromPoint:
Expand All @@ -261,36 +262,38 @@ void Fixture::projectAndMap() {
case _2D: //2D2D: inverse mapping
float minDistance = 10;
// USER_PRINTF("checking indexV %d\n", indexV);
for (forUnsigned16 y=0; y<leds->size.y && minDistance > 0.5f; y++)
for (forUnsigned16 x=0; x<leds->size.x && minDistance > 0.5f; x++) {
// float xFactor = x * TWO_PI / (float)(leds->size.x-1); //between 0 .. 2PI

float xFactor = x * TWO_PI / (float)(leds->size.x-1); //between 0 .. 2PI
float xNew = trigo.sin(leds->size.x, x, leds->size.x-1);
float yNew = trigo.cos(leds->size.y, x, leds->size.x-1);

float xNew = sinf(xFactor) * leds->size.x; //between - .. + size.x
float yNew = cosf(xFactor) * leds->size.y; //between - .. + size.y
for (forUnsigned16 y=0; y<leds->size.y && minDistance > 0.5f; y++) {

float yFactor = (leds->size.y-1.0f-y) / (leds->size.y-1.0f); // between 1 .. 0
// float yFactor = (leds->size.y-1.0f-y) / (leds->size.y-1.0f); // between 1 .. 0
float yFactor = 1 - y / (leds->size.y-1.0f); // between 1 .. 0

xNew = round((yFactor * xNew + leds->size.x) / 2.0f); // 0 .. size.x
yNew = round((yFactor * yNew + leds->size.y) / 2.0f); // 0 .. size.y
float x2New = round((yFactor * xNew + leds->size.x) / 2.0f); // 0 .. size.x
float y2New = round((yFactor * yNew + leds->size.y) / 2.0f); // 0 .. size.y

// USER_PRINTF(" %d,%d->%f,%f->%f,%f", x, y, sinf(x * TWO_PI / (float)(size.x-1)), cosf(x * TWO_PI / (float)(size.x-1)), xNew, yNew);
// USER_PRINTF(" %d,%d->%f,%f->%f,%f", x, y, sinf(x * TWO_PI / (float)(size.x-1)), cosf(x * TWO_PI / (float)(size.x-1)), xNew, yNew);

//this should work (better) but needs more testing
// float distance = abs(indexV - xNew - yNew * size.x);
// if (distance < minDistance) {
// minDistance = distance;
// indexV = x+y*size.x;
// }
//this should work (better) but needs more testing
// float distance = abs(indexV - xNew - yNew * size.x);
// if (distance < minDistance) {
// minDistance = distance;
// indexV = x+y*size.x;
// }

// if the new XY i
if (indexV == leds->XY(xNew, yNew)) { //(unsigned8)xNew + (unsigned8)yNew * size.x) {
// USER_PRINTF(" found one %d => %d=%d+%d*%d (%f+%f*%d) [%f]\n", indexV, x+y*size.x, x,y, size.x, xNew, yNew, size.x, distance);
indexV = leds->XY(x, y);
// if the new XY i
if (indexV == leds->XY(x2New, y2New)) { //(unsigned8)xNew + (unsigned8)yNew * size.x) {
// USER_PRINTF(" found one %d => %d=%d+%d*%d (%f+%f*%d) [%f]\n", indexV, x+y*size.x, x,y, size.x, xNew, yNew, size.x, distance);
indexV = leds->XY(x, y);

if (indexV%10 == 0) USER_PRINTF("."); //show some progress as this projection is slow (Need S007 to optimize ;-)

minDistance = 0.0f; // stop looking further
if (indexV%10 == 0) USER_PRINTF("."); //show some progress as this projection is slow (Need S007 to optimize ;-)

minDistance = 0.0f; // stop looking further
}
}
}
if (minDistance > 0.5f) indexV = UINT16_MAX;
Expand Down
65 changes: 65 additions & 0 deletions src/App/LedLeds.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,71 @@ enum Projections
p_count
};

#define trigoInt8 0
#define trigoInt16 1 //default
#define trigoFloat 2
// sin8/cos8 sin16/cos16
//0: 128, 255 0 32645
//64: 255, 128 32645 0
//128: 128, 1 0 -32645
//192: 1, 127 -32645 0

struct Trigo {
float sinValue; uint16_t sinAngle = UINT16_MAX; //caching of sinValue=sin(sinAngle)
float cosValue; uint16_t cosAngle = UINT16_MAX; //caching of cosValue=cos(cosAngle)
uint8_t type = trigoInt16;
Trigo(uint8_t type = trigoInt16) {
this->type = type;
}
int16_t sin(int16_t factor, uint16_t angle, uint16_t period = 360) {
if (sinAngle != angle) {
sinAngle = angle;
sinValue = type==trigoInt16?sin16(65536.0f * angle / period) / 32645.0f:
type==trigoInt8?(sin8(256.0f * angle / period) - 128) / 127.0f:
sinf(DEG_TO_RAD * 360 * angle / period);
} else USER_PRINTF("%d", type); //debug show cache efficiency
return factor * sinValue;
}
int16_t cos(int16_t factor, uint16_t angle, uint16_t period = 360) {
if (cosAngle != angle) {
cosAngle = angle;
cosValue = type==trigoInt16?cos16(65536.0f * angle / period) / 32645.0f:
type==trigoInt8?(cos8(256.0f * angle / period) - 128) / 127.0f:
cosf(DEG_TO_RAD * 360 * angle / period);
} else USER_PRINTF("%d", type); //debug show cache efficiency
return factor * cosValue;
}
// https://msl.cs.uiuc.edu/planning/node102.html
Coord3D rotateRoll(Coord3D in, Coord3D middle, uint16_t roll) {
Coord3D inM = in - middle;
Coord3D out;
out.x = cos(inM.x, roll) - sin(inM.y, roll);
out.y = sin(inM.x, roll) + cos(inM.y, roll);
out.z = inM.z;
return out + middle;
}
Coord3D rotatePan(Coord3D in, Coord3D middle, uint16_t pan) {
Coord3D inM = in - middle;
Coord3D out;
out.x = cos(inM.x, pan) + sin(inM.z, pan);
out.y = inM.y;
out.z = - sin(inM.x, pan) + cos(inM.z, pan);
return out + middle;
}
Coord3D rotateTilt(Coord3D in, Coord3D middle, uint16_t tilt) {
Coord3D inM = in - middle;
Coord3D out;
out.x = inM.x;
out.y = cos(inM.y, tilt) - sin(inM.z, tilt);
out.z = sin(inM.y, tilt) + cos(inM.z, tilt);
return out + middle;
}
Coord3D rotate(Coord3D in, Coord3D middle, uint16_t pan, uint16_t tilt, uint16_t roll) {
return rotateRoll(rotateTilt(rotatePan(in, middle, pan), middle, tilt), middle, roll);
}
};


class Fixture; //forward


Expand Down
14 changes: 2 additions & 12 deletions src/App/LedModEffects.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,6 @@

#include "SysModule.h"

// FastLED optional flags to configure drivers, see https://github.com/FastLED/FastLED/blob/master/src/platforms/esp/32
// RMT driver (default)
// #define FASTLED_ESP32_FLASH_LOCK 1 // temporarily disabled FLASH file access while driving LEDs (may prevent random flicker)
// #define FASTLED_RMT_BUILTIN_DRIVER 1 // in case your app needs to use RMT units, too (slower)
// I2S parallel driver
// #define FASTLED_ESP32_I2S true // to use I2S parallel driver (instead of RMT)
// #define I2S_DEVICE 1 // I2S driver: allows to still use I2S#0 for audio (only on esp32 and esp32-s3)
// #define FASTLED_I2S_MAX_CONTROLLERS 8 // 8 LED pins should be enough (default = 24)
#include "FastLED.h"

#include "LedFixture.h"
#include "LedEffects.h"

Expand Down Expand Up @@ -161,7 +151,7 @@ class LedModEffects:public SysModule {
return true;
case f_ChangeFun:
//initiate projectAndMap
fixture.projections[rowNr]->doMap = true;
fixture.projections[rowNr]->doMap = true; //Guru Meditation Error: Core 1 panic'ed (StoreProhibited). Exception was unhandled.
fixture.doMap = true;
// ui->setLabel(var, "Size");
return true;
Expand Down Expand Up @@ -356,7 +346,7 @@ class LedModEffects:public SysModule {

#ifdef STARMOD_USERMOD_WLEDAUDIO

if (mdl->getValue("mHead") ) {
if (mdl->getValue("viewRot") == 2) {
fixture.head.x = wledAudioMod->fftResults[3];
fixture.head.y = wledAudioMod->fftResults[8];
fixture.head.z = wledAudioMod->fftResults[13];
Expand Down
74 changes: 46 additions & 28 deletions src/App/LedModFixture.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class LedModFixture:public SysModule {

public:

uint8_t viewRotation = 0;

LedModFixture() :SysModule("Fixture") {};

void setup() {
Expand Down Expand Up @@ -50,7 +52,7 @@ class LedModFixture:public SysModule {
currentVar["log"] = true; //logarithmic
currentVar["dash"] = true; //these values override model.json???

ui->initCanvas(parentVar, "pview", UINT16_MAX, false, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
currentVar = ui->initCanvas(parentVar, "pview", UINT16_MAX, false, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_UIFun:
ui->setLabel(var, "Preview");
// ui->setComment(var, "Shows the fixture");
Expand All @@ -73,17 +75,47 @@ class LedModFixture:public SysModule {
}
//new values
buffer[0] = 1; //userFun id
buffer[1] = eff->fixture.head.x;
buffer[2] = eff->fixture.head.y;
buffer[3] = eff->fixture.head.y;
//rotations
if (viewRotation == 0) {
buffer[1] = 0;
buffer[2] = 0;
buffer[3] = 0;
} else if (viewRotation == 1) {
buffer[1] = 0;//beatsin8(4, 250, 5); //tilt
buffer[2] = beat8(1);//, 0, 255); //pan
buffer[3] = 0;//beatsin8(6, 255, 5); //roll
} else if (viewRotation == 2) {
buffer[1] = eff->fixture.head.x;
buffer[2] = eff->fixture.head.y;
buffer[3] = eff->fixture.head.y;
}

}, eff->fixture.nrOfLeds * 3 + 5, true);
return true;
}
default: return false;
}});

ui->initSelect(parentVar, "fixture", eff->fixture.fixtureNr, false ,[](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
ui->initSelect(currentVar, "viewRot", viewRotation, false, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_UIFun: {
ui->setLabel(var, "Rotation");
// ui->setComment(var, "View rotation");
JsonArray options = ui->setOptions(var);
options.add("None");
options.add("Pan");
#ifdef STARMOD_USERMOD_WLEDAUDIO
options.add("Moving heads GEQ");
#endif
return true; }
case f_ChangeFun:
this->viewRotation = var["value"];
// if (!var["value"])
// eff->fixture.head = {0,0,0};
return true;
default: return false;
}});

currentVar = ui->initSelect(parentVar, "fixture", eff->fixture.fixtureNr, false ,[](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_UIFun:
{
// ui->setComment(var, "Fixture to display effect on");
Expand Down Expand Up @@ -119,7 +151,7 @@ class LedModFixture:public SysModule {
default: return false;
}}); //fixture

ui->initCoord3D(parentVar, "fixSize", eff->fixture.size, 0, NUM_LEDS_Max, true, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
ui->initCoord3D(currentVar, "fixSize", eff->fixture.size, 0, NUM_LEDS_Max, true, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_ValueFun:
mdl->setValue(var, eff->fixture.size);
return true;
Expand All @@ -129,7 +161,7 @@ class LedModFixture:public SysModule {
default: return false;
}});

ui->initNumber(parentVar, "fixCount", eff->fixture.nrOfLeds, 0, UINT16_MAX, true, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
ui->initNumber(currentVar, "fixCount", eff->fixture.nrOfLeds, 0, UINT16_MAX, true, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_ValueFun:
mdl->setValue(var, eff->fixture.nrOfLeds);
return true;
Expand All @@ -150,6 +182,13 @@ class LedModFixture:public SysModule {
default: return false;
}});

ui->initText(parentVar, "realFps", nullptr, 10, true, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_UIFun:
web->addResponseV(var["id"], "comment", "f(%d leds)", eff->fixture.nrOfLeds);
return true;
default: return false;
}});

ui->initCheckBox(parentVar, "fShow", eff->fShow, false, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_UIFun:
ui->setLabel(var, "FastLed show");
Expand All @@ -161,27 +200,6 @@ class LedModFixture:public SysModule {
default: return false;
}});

ui->initText(parentVar, "realFps", nullptr, 10, true, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_UIFun:
web->addResponseV(var["id"], "comment", "f(%d leds)", eff->fixture.nrOfLeds);
return true;
default: return false;
}});

#ifdef STARMOD_USERMOD_WLEDAUDIO
ui->initCheckBox(parentVar, "mHead", false, false, [](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_UIFun:
ui->setLabel(var, "Moving heads");
ui->setComment(var, "Move on GEQ");
return true;
case f_ChangeFun:
if (!var["value"])
eff->fixture.head = {0,0,0};
return true;
default: return false;
}});
#endif

}
};

Expand Down
Loading

0 comments on commit 826a417

Please sign in to comment.