Skip to content

Commit

Permalink
projection classes: create methods and use in projectAndMap and XYZ
Browse files Browse the repository at this point in the history
LedEffects: GOL: rename XYZNoSpin to XYZUnprojected

LedFixture
- Move Projection class here so Fixture and Leds can use it to call members of derived classes
- Add Fixture.projections
- projectAndMap: use projection->adjustSizeAndPixel and adjustMapped and move code to projection classes (WIP)

LedLeds:
- make projection none the first option
- refactor XYZ, XYZ uses projection.adjustXYZ

LedModEffects: push projections to fixture.projections (instead of LedModEffects.projections

LedProjections
- MultiplyProjection: add adjustSizeAndPixel and adjustMapped
- TiltPanRollProjection: add adjustXYZ
- Preset1Projection: call 'inherited' functions (WIP)
  • Loading branch information
ewoudwijma committed Jun 22, 2024
1 parent 81280c5 commit 4322c3e
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 124 deletions.
16 changes: 8 additions & 8 deletions src/App/LedEffects.h
Original file line number Diff line number Diff line change
Expand Up @@ -1373,13 +1373,13 @@ class GameOfLife: public Effect {
for (int i = 0; i < 5; i++) {
int nx = x + pattern[i][0];
int ny = y + pattern[i][1];
if (getBitValue(futureCells, leds.XYZNoSpin({nx, ny, z}))) {canPlace = false; break;}
if (getBitValue(futureCells, leds.XYZUnprojected({nx, ny, z}))) {canPlace = false; break;}
}
if (canPlace || attempts == 99) {
for (int i = 0; i < 5; i++) {
int nx = x + pattern[i][0];
int ny = y + pattern[i][1];
setBitValue(futureCells, leds.XYZNoSpin({nx, ny, z}), true);
setBitValue(futureCells, leds.XYZUnprojected({nx, ny, z}), true);
leds.setPixelColor({nx, ny, z}, colorByAge ? CRGB::Green : color, 0);
}
return;
Expand Down Expand Up @@ -1430,9 +1430,9 @@ class GameOfLife: public Effect {
// Setup Grid
memset(cells, 0, dataSize);
for (int x = 0; x < leds.size.x; x++) for (int y = 0; y < leds.size.y; y++) for (int z = 0; z < leds.size.z; z++){
if (leds.projectionDimension == _3D && !leds.isMapped(leds.XYZNoSpin({x,y,z}))) continue;
if (leds.projectionDimension == _3D && !leds.isMapped(leds.XYZUnprojected({x,y,z}))) continue;
if (random8(100) < lifeChance) {
setBitValue(cells, leds.XYZNoSpin({x,y,z}), true);
setBitValue(cells, leds.XYZUnprojected({x,y,z}), true);
leds.setPixelColor({x,y,z}, colorByAge ? CRGB::Green : ColorFromPalette(leds.palette, random8()), 0);
}
else leds.setPixelColor({x,y,z}, bgColor, 0);
Expand Down Expand Up @@ -1463,8 +1463,8 @@ class GameOfLife: public Effect {
if (paletteChanged) *prevPalette = ColorFromPalette(leds.palette, 0);
// Redraw Loop
for (int x = 0; x < leds.size.x; x++) for (int y = 0; y < leds.size.y; y++) for (int z = 0; z < leds.size.z; z++){
if (!leds.isMapped(leds.XYZNoSpin({x,y,z}))) continue;
bool alive = getBitValue(cells, leds.XYZNoSpin({x,y,z}));
if (!leds.isMapped(leds.XYZUnprojected({x,y,z}))) continue;
bool alive = getBitValue(cells, leds.XYZUnprojected({x,y,z}));
if (alive) aliveCount++; else deadCount++;
// Redraw alive if palette changed or overlay1
if (alive && paletteChanged) leds.setPixelColor({x,y,z}, ColorFromPalette(leds.palette, random8()), 0); // Random color if palette changed
Expand Down Expand Up @@ -1509,7 +1509,7 @@ class GameOfLife: public Effect {
//Loop through all cells. Count neighbors, apply rules, setPixel
for (int x = 0; x < leds.size.x; x++) for (int y = 0; y < leds.size.y; y++) for (int z = 0; z < leds.size.z; z++){
Coord3D cPos = {x, y, z}; //current cells position
uint16_t cIndex = leds.XYZNoSpin(cPos);
uint16_t cIndex = leds.XYZUnprojected(cPos);
if (leds.projectionDimension == _3D && !leds.isMapped(leds.XYZ(x,y,z))) continue; //skip if not physical led
byte neighbors = 0;
byte colorCount = 0; //track number of valid colors
Expand All @@ -1524,7 +1524,7 @@ class GameOfLife: public Effect {
if (k != 0) continue; //no z axis (wrap around only for x and y
nPos = (nPos + leds.size) % leds.size;
}
uint16_t nIndex = leds.XYZNoSpin(nPos);
uint16_t nIndex = leds.XYZUnprojected(nPos);
// count neighbors and store up to 9 neighbor colors
if (getBitValue(cells, nIndex)) { //if alive
neighbors++;
Expand Down
59 changes: 18 additions & 41 deletions src/App/LedFixture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,27 +102,12 @@ void Fixture::projectAndMap() {
if (sizeAdjusted.y > 1) leds->projectionDimension++;
if (sizeAdjusted.z > 1) leds->projectionDimension++;

Coord3D proCenter;
if (leds->projectionNr == p_DistanceFromPoint || leds->projectionNr == p_Preset1) {
proCenter = mdl->getValue("proCenter", rowNr);
}
else
proCenter = Coord3D{0,0,0};

Coord3D mirrors = Coord3D{0,0,0}; // no mirrors
if (leds->projectionNr == p_Multiply || leds->projectionNr == p_Preset1) {
Coord3D proMulti;
proMulti = mdl->getValue("proMulti", rowNr);
//promultu can be 0,0,0 but /= protects from /div0
sizeAdjusted /= proMulti; sizeAdjusted = sizeAdjusted.maximum(Coord3D{1,1,1}); //size min 1,1,1
proCenter /= proMulti;
mirrors = pixelAdjusted / sizeAdjusted; //place the pixel in the right quadrant
pixelAdjusted = pixelAdjusted%sizeAdjusted; // pixel % size
// ppf("Multiply %d,%d,%d\n", leds->size.x, leds->size.y, leds->size.z);
}
bool mirror = mdl->getValue("mirror", rowNr);
Projection *projection = projections[leds->projectionNr];
mdl->getValueRowNr = rowNr; //run projection functions in the right rowNr context

Coord3D proCenter = mdl->getValue("proCenter", rowNr);

// ppf("projectionNr p:%d f:%d s:%d, %d-%d-%d %d-%d-%d %d-%d-%d\n", leds->projectionNr, leds->effectDimension, leds->projectionDimension, x, y, z, uint16CollectList[0], uint16CollectList[1], uint16CollectList[2], size.x, size.y, size.z);
projection->adjustSizeAndPixel(sizeAdjusted, pixelAdjusted, proCenter);

if (leds->size == Coord3D{0,0,0}) { // first
ppf("projectAndMap first leds[%d] size:%d,%d,%d s:%d,%d,%d e:%d,%d,%d\n", rowNr, sizeAdjusted.x, sizeAdjusted.y, sizeAdjusted.z, startPosAdjusted.x, startPosAdjusted.y, startPosAdjusted.z, endPosAdjusted.x, endPosAdjusted.y, endPosAdjusted.z);
Expand All @@ -142,18 +127,13 @@ void Fixture::projectAndMap() {

mapped = pixelAdjusted;

// if mirrored find the indexV of the mirrored pixel
if (mirror) {
if (mirrors.x %2 != 0) mapped.x = sizeAdjusted.x - 1 - mapped.x;
if (mirrors.y %2 != 0) mapped.y = sizeAdjusted.y - 1 - mapped.y;
if (mirrors.z %2 != 0) mapped.z = sizeAdjusted.z - 1 - mapped.z;
}
projection->adjustMapped(mapped, sizeAdjusted, (pixel - startPosAdjusted)/10);

mapped.x = mapped.distance(proCenter);
mapped.y = 0;
mapped.z = 0;

indexV = leds->XYZNoSpin(mapped);
indexV = leds->XYZUnprojected(mapped);
break;
case _2D: //effectDimension
switch(leds->projectionDimension) {
Expand Down Expand Up @@ -205,12 +185,9 @@ void Fixture::projectAndMap() {
break;
}

if (mirror) {
if (mirrors.x %2 != 0) mapped.x = sizeAdjusted.x - 1 - mapped.x;
if (mirrors.y %2 != 0) mapped.y = sizeAdjusted.y - 1 - mapped.y;
if (mirrors.z %2 != 0) mapped.z = sizeAdjusted.z - 1 - mapped.z;
}
indexV = leds->XYZNoSpin(mapped);
projection->adjustMapped(mapped, sizeAdjusted, (pixel - startPosAdjusted)/10);

indexV = leds->XYZUnprojected(mapped);
break;
case _3D: //effectDimension
mapped = pixelAdjusted;
Expand Down Expand Up @@ -238,12 +215,10 @@ void Fixture::projectAndMap() {
}
break;
}
if (mirror) {
if (mirrors.x %2 != 0) mapped.x = sizeAdjusted.x - 1 - mapped.x;
if (mirrors.y %2 != 0) mapped.y = sizeAdjusted.y - 1 - mapped.y;
if (mirrors.z %2 != 0) mapped.z = sizeAdjusted.z - 1 - mapped.z;
}
indexV = leds->XYZNoSpin(mapped);

projection->adjustMapped(mapped, sizeAdjusted, (pixel - startPosAdjusted)/10);

indexV = leds->XYZUnprojected(mapped);

break; //effectDimension _3D
} //effectDimension
Expand Down Expand Up @@ -329,10 +304,12 @@ void Fixture::projectAndMap() {
} //indexV not too high
} //indexV

mdl->getValueRowNr = UINT8_MAX; // end of run projection functions in the right rowNr context

} //if x,y,z between start and endpos
} //leds->doMap
} //if leds->doMap
rowNr++;
} //listOfLeds
} //for listOfLeds
indexP++; //also increase if no buffer created
} //if 1D-3D pixel

Expand Down
18 changes: 18 additions & 0 deletions src/App/LedFixture.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,22 @@

class Leds; //forward

class Projection {
public:
virtual const char * name() {return "noname";}
virtual const char * tags() {return "";}
virtual uint8_t dim() {return _1D;};

virtual void adjustSizeAndPixel(Coord3D &sizeAdjusted, Coord3D &pixelAdjusted, Coord3D &proCenter) {}

virtual void adjustMapped(Coord3D &mapped, Coord3D sizeAdjusted, Coord3D pixelAdjusted) {}

virtual void adjustXYZ(Leds &leds, Coord3D &pixel) {}

virtual void controls(Leds &leds, JsonObject parentVar) {}

};

class Fixture {

public:
Expand All @@ -39,6 +55,8 @@ class Fixture {
// leds = (CRGB*)malloc(nrOfLeds * sizeof(CRGB));
// leds = (CRGB*)reallocarray

std::vector<Projection *> projections;

unsigned16 nrOfLeds = 64; //amount of physical leds
unsigned8 fixtureNr = -1;
Coord3D fixSize = {8,8,1};
Expand Down
28 changes: 12 additions & 16 deletions src/App/LedLeds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
*/

#include "LedLeds.h"
#include "../Sys/SysModSystem.h"

#include "../Sys/SysModSystem.h" //for sys->now

//convenience functions to call fastled functions out of the Leds namespace (there naming conflict)
void fastled_fadeToBlackBy(CRGB* leds, unsigned16 num_leds, unsigned8 fadeBy) {
Expand All @@ -23,20 +24,15 @@ void fastled_fill_rainbow(struct CRGB * targetArray, int numToFill, unsigned8 in
fill_rainbow(targetArray, numToFill, initialhue, deltahue);
}

unsigned16 Leds::XYZ(unsigned16 x, unsigned16 y, unsigned16 z) {
if (projectionNr == p_TiltPanRoll || projectionNr == p_Preset1) {
Coord3D result = Coord3D{x, y, z};
if (proTiltSpeed) result = trigoTiltPanRoll.tilt(result, size/2, sys->now * 5 / (255 - proTiltSpeed));
if (proPanSpeed) result = trigoTiltPanRoll.pan(result, size/2, sys->now * 5 / (255 - proPanSpeed));
if (proRollSpeed) result = trigoTiltPanRoll.roll(result, size/2, sys->now * 5 / (255 - proRollSpeed));
if (fixture->fixSize.z == 1) result.z = 0; // 3d effects will be flattened on 2D fixtures
if (result >= 0 && result < size)
return result.x + result.y * size.x + result.z * size.x * size.y;
else
return UINT16_MAX;
}
else
return x + y * size.x + z * size.x * size.y;
unsigned16 Leds::XYZ(Coord3D pixel) {

//as this is a call to a virtual function it reduces the theoretical (no show) speed by half, even if XYZ is not implemented
// the real speed is hardly affected, but room for improvement!
// so as a workaround we list them here explicetly
if (projectionNr == p_TiltPanRoll || projectionNr == p_Preset1)
fixture->projections[projectionNr]->adjustXYZ(*this, pixel);

return XYZUnprojected(pixel);
}

// maps the virtual led to the physical led(s) and assign a color to it
Expand All @@ -55,7 +51,7 @@ void Leds::setPixelColor(unsigned16 indexV, CRGB color, unsigned8 blendAmount) {
}
}
else if (indexV < NUM_LEDS_Max) //no projection
fixture->ledsP[projectionNr==p_Random?random(fixture->nrOfLeds):indexV] = color;
fixture->ledsP[(projectionNr == p_Random)?random(fixture->nrOfLeds):indexV] = color;
else if (indexV != UINT16_MAX) //assuming UINT16_MAX is set explicitly (e.g. in XYZ)
ppf(" dev sPC V:%d >= %d", indexV, NUM_LEDS_Max);
}
Expand Down
15 changes: 9 additions & 6 deletions src/App/LedLeds.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@

enum ProjectionsE
{
p_None,
p_Default,
p_Multiply,
p_TiltPanRoll,
p_DistanceFromPoint,
p_Preset1,
p_None,
p_Random,
p_Reverse,
p_Mirror,
Expand Down Expand Up @@ -287,15 +287,18 @@ class Leds {
return XYZ(x, y, 0);
}

unsigned16 XYZNoSpin(Coord3D coord) {
return coord.x + coord.y * size.x + coord.z * size.x * size.y;
unsigned16 XYZUnprojected(Coord3D pixel) {
if (pixel >= 0 && pixel < size)
return pixel.x + pixel.y * size.x + pixel.z * size.x * size.y;
else
return UINT16_MAX;
}

unsigned16 XYZ(Coord3D coord) {
return XYZ(coord.x, coord.y, coord.z);
unsigned16 XYZ(unsigned16 x, unsigned16 y, unsigned16 z) {
return XYZ({x, y, z});
}

unsigned16 XYZ(unsigned16 x, unsigned16 y, unsigned16 z);
unsigned16 XYZ(Coord3D pixel);

Leds(Fixture &fixture) {
ppf("Leds constructor (PhysMap:%d)\n", sizeof(PhysMap));
Expand Down
40 changes: 20 additions & 20 deletions src/App/LedModEffects.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class LedModEffects:public SysModule {
unsigned long lastMappingMillis = 0;

std::vector<Effect *> effects;
std::vector<Projection *> projections;

Fixture fixture = Fixture();

Expand Down Expand Up @@ -97,16 +96,16 @@ class LedModEffects:public SysModule {
effects.push_back(new SphereMoveEffect);

//load projections
projections.push_back(new DefaultProjection);
projections.push_back(new MultiplyProjection);
projections.push_back(new TiltPanRollProjection);
projections.push_back(new DistanceFromPointProjection);
projections.push_back(new Preset1Projection);
projections.push_back(new NoneProjection);
projections.push_back(new RandomProjection);
projections.push_back(new ReverseProjection);
projections.push_back(new MirrorProjection);
projections.push_back(new KaleidoscopeProjection);
fixture.projections.push_back(new NoneProjection);
fixture.projections.push_back(new DefaultProjection);
fixture.projections.push_back(new MultiplyProjection);
fixture.projections.push_back(new TiltPanRollProjection);
fixture.projections.push_back(new DistanceFromPointProjection);
fixture.projections.push_back(new Preset1Projection);
fixture.projections.push_back(new RandomProjection);
fixture.projections.push_back(new ReverseProjection);
fixture.projections.push_back(new MirrorProjection);
fixture.projections.push_back(new KaleidoscopeProjection);
};

void setup() {
Expand Down Expand Up @@ -208,7 +207,8 @@ class LedModEffects:public SysModule {
}});
currentVar["dash"] = true;

currentVar = ui->initSelect(tableVar, "pro", 2, false, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
//projection, default projection is 'default'
currentVar = ui->initSelect(tableVar, "pro", 1, false, [this](JsonObject var, unsigned8 rowNr, unsigned8 funType) { switch (funType) { //varFun
case f_ValueFun:
for (forUnsigned8 rowNr = 0; rowNr < fixture.listOfLeds.size(); rowNr++)
mdl->setValue(var, fixture.listOfLeds[rowNr]->projectionNr, rowNr);
Expand All @@ -218,7 +218,7 @@ class LedModEffects:public SysModule {
ui->setComment(var, "How to project fx");

JsonArray options = ui->setOptions(var);
for (Projection *projection:projections) {
for (Projection *projection:fixture.projections) {
char buf[32] = "";
strcat(buf, projection->name());
strcat(buf, projection->dim()==_1D?"":projection->dim()==_2D?"":" 🧊");
Expand All @@ -232,15 +232,15 @@ class LedModEffects:public SysModule {
if (rowNr == UINT8_MAX) rowNr = 0; // in case fx without a rowNr

if (rowNr < fixture.listOfLeds.size()) {
fixture.listOfLeds[rowNr]->doMap = true;
Leds *leds = fixture.listOfLeds[rowNr];
leds->doMap = true;

stackUnsigned8 proValue = mdl->getValue(var, rowNr);
fixture.listOfLeds[rowNr]->projectionNr = proValue;

Projection* projection = projections[proValue];
leds->projectionNr = proValue;
Projection* projection = fixture.projections[proValue];

mdl->varPreDetails(var, rowNr); //set all positive var N orders to negative
projection->controls(*fixture.listOfLeds[rowNr], var);
projection->controls(*leds, var);
mdl->varPostDetails(var, rowNr);

// ppf("chFun pro[%d] <- %d (%d)\n", rowNr, proValue, fixture.listOfLeds.size());
Expand Down Expand Up @@ -387,8 +387,8 @@ class LedModEffects:public SysModule {
effects[leds->fx]->loop(*leds);

mdl->getValueRowNr = UINT8_MAX;
if (leds->projectionNr == p_TiltPanRoll || leds->projectionNr == p_Preset1)
leds->fadeToBlackBy(50);
// if (leds->projectionNr == p_TiltPanRoll || leds->projectionNr == p_Preset1)
// leds->fadeToBlackBy(50);
}
}

Expand Down
Loading

0 comments on commit 4322c3e

Please sign in to comment.