mirror of
https://github.com/wled/WLED.git
synced 2025-12-24 08:58:19 +00:00
Compare commits
4 Commits
copilot/fi
...
rotate-zoo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
252311b4f5 | ||
|
|
201c3c0066 | ||
|
|
35f9b37a33 | ||
|
|
9da047f872 |
11
wled00/FX.h
11
wled00/FX.h
@@ -421,7 +421,7 @@ typedef enum mapping1D2D {
|
||||
|
||||
class WS2812FX;
|
||||
|
||||
// segment, 76 bytes
|
||||
// segment, 80 bytes
|
||||
class Segment {
|
||||
public:
|
||||
uint32_t colors[NUM_COLORS];
|
||||
@@ -460,9 +460,12 @@ class Segment {
|
||||
bool check1 : 1; // checkmark 1
|
||||
bool check2 : 1; // checkmark 2
|
||||
bool check3 : 1; // checkmark 3
|
||||
//uint8_t blendMode : 4; // segment blending modes: top, bottom, add, subtract, difference, multiply, divide, lighten, darken, screen, overlay, hardlight, softlight, dodge, burn
|
||||
};
|
||||
uint8_t blendMode; // segment blending modes: top, bottom, add, subtract, difference, multiply, divide, lighten, darken, screen, overlay, hardlight, softlight, dodge, burn
|
||||
struct {
|
||||
uint8_t zoomAmount : 4; // zoom amount (0-15); 8 == no zoom
|
||||
uint8_t rotateSpeed : 4; // rotation speed (0-15); 0 == no rotation
|
||||
};
|
||||
char *name; // segment name
|
||||
|
||||
// runtime data
|
||||
@@ -488,6 +491,7 @@ class Segment {
|
||||
bool _manualW : 1;
|
||||
};
|
||||
};
|
||||
mutable uint16_t _rotatedAngle; // current rotation angle (2D)
|
||||
|
||||
// static variables are use to speed up effect calculations by stashing common pre-calculated values
|
||||
static unsigned _usedSegmentData; // amount of data used by all segments
|
||||
@@ -591,6 +595,8 @@ class Segment {
|
||||
, check2(false)
|
||||
, check3(false)
|
||||
, blendMode(0)
|
||||
, zoomAmount(8)
|
||||
, rotateSpeed(0)
|
||||
, name(nullptr)
|
||||
, next_time(0)
|
||||
, step(0)
|
||||
@@ -601,6 +607,7 @@ class Segment {
|
||||
, _dataLen(0)
|
||||
, _default_palette(6)
|
||||
, _capabilities(0)
|
||||
, _rotatedAngle(0)
|
||||
, _t(nullptr)
|
||||
{
|
||||
DEBUGFX_PRINTF_P(PSTR("-- Creating segment: %p [%d,%d:%d,%d]\n"), this, (int)start, (int)stop, (int)startY, (int)stopY);
|
||||
|
||||
@@ -563,7 +563,7 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
sOpt = extractModeDefaults(fx, "ix"); intensity = (sOpt >= 0) ? sOpt : DEFAULT_INTENSITY;
|
||||
sOpt = extractModeDefaults(fx, "c1"); custom1 = (sOpt >= 0) ? sOpt : DEFAULT_C1;
|
||||
sOpt = extractModeDefaults(fx, "c2"); custom2 = (sOpt >= 0) ? sOpt : DEFAULT_C2;
|
||||
sOpt = extractModeDefaults(fx, "c3"); custom3 = (sOpt >= 0) ? sOpt : DEFAULT_C3;
|
||||
sOpt = extractModeDefaults(fx, "c3"); custom3 = (sOpt >= 0) ? constrain(sOpt, 0, 31) : DEFAULT_C3;
|
||||
sOpt = extractModeDefaults(fx, "o1"); check1 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
sOpt = extractModeDefaults(fx, "o2"); check2 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
sOpt = extractModeDefaults(fx, "o3"); check3 = (sOpt >= 0) ? (bool)sOpt : false;
|
||||
@@ -573,6 +573,8 @@ Segment &Segment::setMode(uint8_t fx, bool loadDefaults) {
|
||||
sOpt = extractModeDefaults(fx, "mi"); if (sOpt >= 0) mirror = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "rY"); if (sOpt >= 0) reverse_y = (bool)sOpt;
|
||||
sOpt = extractModeDefaults(fx, "mY"); if (sOpt >= 0) mirror_y = (bool)sOpt; // NOTE: setting this option is a risky business
|
||||
sOpt = extractModeDefaults(fx, "rS"); if (sOpt >= 0) rotateSpeed = constrain(sOpt, 0, 15); // 0 = no rotation
|
||||
sOpt = extractModeDefaults(fx, "zA"); if (sOpt >= 0) zoomAmount = constrain(sOpt, 0, 15); // 8 = no zoom
|
||||
}
|
||||
sOpt = extractModeDefaults(fx, "pal"); // always extract 'pal' to set _default_palette
|
||||
if (sOpt >= 0 && loadDefaults) setPalette(sOpt);
|
||||
@@ -1474,9 +1476,109 @@ void WS2812FX::blendSegment(const Segment &topSegment) const {
|
||||
}
|
||||
};
|
||||
|
||||
// zooming and rotation
|
||||
auto RotateAndZoom = [](uint32_t *srcPixels, uint32_t *destPixels, int midX, int midY, int cols, int rows, int shearAngle, int zoomOffset) {
|
||||
for (int i = 0; i < cols * rows; i++) destPixels[i] = BLACK; // fill black
|
||||
|
||||
constexpr uint8_t Scale_Shift = 10;
|
||||
constexpr int Fixed_Scale = (1 << Scale_Shift);
|
||||
constexpr int RoundVal = (1 << (Scale_Shift - 1));
|
||||
constexpr int zoomRange = (Fixed_Scale * 3) / 4; // 768
|
||||
int zoomScale = Fixed_Scale + (zoomOffset * zoomRange) / 8; // zoomOffset: -8 .. +7 -> zoomScale: 256 .. 1696
|
||||
if (zoomScale <= 0) zoomScale = 1; // avoid divide-by-zero and negative zoom
|
||||
|
||||
const bool flip = (shearAngle > 90 && shearAngle < 270); // Flip to avoid instability near 180°
|
||||
if (flip) shearAngle = (shearAngle + 180) % 360;
|
||||
|
||||
// Calculate shearX and shearY
|
||||
const float angleRadians = radians(shearAngle);
|
||||
int shearX = -tan_t(angleRadians / 2) * Fixed_Scale;
|
||||
int shearY = sin_t(angleRadians) * Fixed_Scale;
|
||||
|
||||
const int WRAP_PAD_X = cols << 5; // ×32
|
||||
const int WRAP_PAD_Y = rows << 5; // Ensures wrap works with large negative coordinates when zoomed out
|
||||
|
||||
// Use inverse mapping: iterate destination pixels, find source coordinates
|
||||
for (int destY = 0; destY < rows; destY++) {
|
||||
for (int destX = 0; destX < cols; destX++) {
|
||||
// Translate destination to origin
|
||||
int dx = destX - midX;
|
||||
int dy = destY - midY;
|
||||
|
||||
// Inverse shear transformations (reverse order)
|
||||
int x1 = dx - ((shearX * dy + RoundVal) >> Scale_Shift);
|
||||
int y0 = dy - ((shearY * x1 + RoundVal) >> Scale_Shift);
|
||||
int x0 = x1 - ((shearX * y0 + RoundVal) >> Scale_Shift);
|
||||
|
||||
// Apply zoom to source coordinates
|
||||
x0 = (x0 * Fixed_Scale) / zoomScale;
|
||||
y0 = (y0 * Fixed_Scale) / zoomScale;
|
||||
|
||||
// Handle flip
|
||||
int srcX = flip ? (midX - x0) : (midX + x0);
|
||||
int srcY = flip ? (midY - y0) : (midY + y0);
|
||||
|
||||
// Bounds check or wrap
|
||||
//if (wrap) { // Wrap around
|
||||
srcX = (srcX + WRAP_PAD_X); while (srcX >= cols) srcX -= cols; // positive modulo since % is slow
|
||||
srcY = (srcY + WRAP_PAD_Y); while (srcY >= rows) srcY -= rows; // positive modulo since % is slow
|
||||
//}
|
||||
//else if (wrap_and_mirror) { // Wrap plus mirror
|
||||
// int tileX = (srcX + WRAP_PAD_X) / cols;
|
||||
// int tileY = (srcY + WRAP_PAD_Y) / rows;
|
||||
|
||||
// // Wrap src
|
||||
// srcX = (srcX + WRAP_PAD_X); while (srcX >= cols) srcX -= cols; // positive modulo since % is slow
|
||||
// srcY = (srcY + WRAP_PAD_Y); while (srcY >= rows) srcY -= rows; // positive modulo since % is slow
|
||||
|
||||
// // Flip on odd tiles
|
||||
// if (tileX & 1) srcX = cols - 1 - srcX;
|
||||
// if (tileY & 1) srcY = rows - 1 - srcY;
|
||||
//}
|
||||
//else
|
||||
if ((unsigned)srcX >= (unsigned)cols || (unsigned)srcY >= (unsigned)rows) continue;
|
||||
|
||||
// Sample from source & write to destination
|
||||
destPixels[destX + destY * cols] = srcPixels[srcX + srcY * cols];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
uint32_t *_pixelsN = topSegment.getPixels(); // we will use this pointer as a source later insetad of getPixelColorRaw()
|
||||
if (topSegment.rotateSpeed || topSegment.zoomAmount != 8) {
|
||||
_pixelsN = new uint32_t[nCols * nRows]; // may use allocateBuffer() if needed
|
||||
const int midX = nCols / 2;
|
||||
const int midY = nRows / 2;
|
||||
if (topSegment.rotateSpeed != 0) {
|
||||
topSegment._rotatedAngle += topSegment.rotateSpeed;
|
||||
while (topSegment._rotatedAngle > 3600) topSegment._rotatedAngle -= 3600;
|
||||
} else {
|
||||
topSegment._rotatedAngle = 0; // reset angle if no rotation
|
||||
}
|
||||
RotateAndZoom(topSegment.getPixels(), _pixelsN, midX, midY, nCols, nRows, topSegment._rotatedAngle/10, topSegment.zoomAmount - 8);
|
||||
}
|
||||
uint32_t *_pixelsO = topSegment.getPixels(); // we will use this pointer as a source (old segment during transition) later insetad of getPixelColorRaw()
|
||||
if (segO) {
|
||||
_pixelsO = segO->getPixels(); // default to unmodified old segment pixels
|
||||
if (segO->rotateSpeed || segO->zoomAmount != 8) {
|
||||
_pixelsO = new uint32_t[oCols * oRows]; // may use allocateBuffer() if needed
|
||||
const int midXo = oCols / 2;
|
||||
const int midYo = oRows / 2;
|
||||
if (segO->rotateSpeed != 0) {
|
||||
segO->_rotatedAngle += segO->rotateSpeed;
|
||||
while (segO->_rotatedAngle > 3600) segO->_rotatedAngle -= 3600;
|
||||
} else {
|
||||
segO->_rotatedAngle = 0;
|
||||
}
|
||||
RotateAndZoom(segO->getPixels(), _pixelsO, midXo, midYo, oCols, oRows, segO->_rotatedAngle/10, segO->zoomAmount - 8);
|
||||
}
|
||||
}
|
||||
|
||||
// if we blend using "push" style we need to "shift" canvas to left/right/up/down
|
||||
unsigned offsetX = (blendingStyle == BLEND_STYLE_PUSH_UP || blendingStyle == BLEND_STYLE_PUSH_DOWN) ? 0 : progInv * nCols / 0xFFFFU;
|
||||
unsigned offsetY = (blendingStyle == BLEND_STYLE_PUSH_LEFT || blendingStyle == BLEND_STYLE_PUSH_RIGHT) ? 0 : progInv * nRows / 0xFFFFU;
|
||||
if (blendingStyle == BLEND_STYLE_PUSH_RIGHT) offsetX = nCols - offsetX;
|
||||
if (blendingStyle == BLEND_STYLE_PUSH_UP) offsetY = nRows - offsetY;
|
||||
|
||||
// we only traverse new segment, not old one
|
||||
for (int r = 0; r < nRows; r++) for (int c = 0; c < nCols; c++) {
|
||||
@@ -1485,22 +1587,19 @@ void WS2812FX::blendSegment(const Segment &topSegment) const {
|
||||
const Segment *seg = clipped && segO ? segO : &topSegment; // pixel is never clipped for FADE
|
||||
int vCols = seg == segO ? oCols : nCols; // old segment may have different dimensions
|
||||
int vRows = seg == segO ? oRows : nRows; // old segment may have different dimensions
|
||||
uint32_t *_pixelsR = seg == segO ? _pixelsO : _pixelsN;
|
||||
int x = c;
|
||||
int y = r;
|
||||
// if we blend using "push" style we need to "shift" canvas to left/right/up/down
|
||||
switch (blendingStyle) {
|
||||
case BLEND_STYLE_PUSH_RIGHT: x = (x + offsetX) % nCols; break;
|
||||
case BLEND_STYLE_PUSH_LEFT: x = (x - offsetX + nCols) % nCols; break;
|
||||
case BLEND_STYLE_PUSH_DOWN: y = (y + offsetY) % nRows; break;
|
||||
case BLEND_STYLE_PUSH_UP: y = (y - offsetY + nRows) % nRows; break;
|
||||
}
|
||||
if (offsetX != 0) { x = (x + offsetX); while (x >= nCols) x -= nCols; }
|
||||
if (offsetY != 0) { y = (y + offsetY); while (y >= nRows) y -= nRows; }
|
||||
uint32_t c_a = BLACK;
|
||||
if (x < vCols && y < vRows) c_a = seg->getPixelColorRaw(x + y*vCols); // will get clipped pixel from old segment or unclipped pixel from new segment
|
||||
if (x < vCols && y < vRows) c_a = _pixelsR[x + y*vCols]; // will get clipped pixel from old segment or unclipped pixel from new segment
|
||||
if (segO && blendingStyle == BLEND_STYLE_FADE
|
||||
&& (topSegment.mode != segO->mode || (segO->name != topSegment.name && segO->name && topSegment.name && strncmp(segO->name, topSegment.name, WLED_MAX_SEGNAME_LEN) != 0))
|
||||
&& x < oCols && y < oRows) {
|
||||
// we need to blend old segment using fade as pixels are not clipped
|
||||
c_a = color_blend16(c_a, segO->getPixelColorRaw(x + y*oCols), progInv);
|
||||
c_a = color_blend16(c_a, _pixelsO[x + y*oCols], progInv);
|
||||
} else if (blendingStyle != BLEND_STYLE_FADE) {
|
||||
// if we have global brightness change (not On/Off change) we will ignore transition style and just fade brightness (see led.cpp)
|
||||
// workaround for On/Off transition
|
||||
@@ -1531,6 +1630,9 @@ void WS2812FX::blendSegment(const Segment &topSegment) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
// clean up
|
||||
if (topSegment.rotateSpeed || topSegment.zoomAmount != 8) delete[] _pixelsN;
|
||||
if (segO && (segO->rotateSpeed || segO->zoomAmount != 8)) delete[] _pixelsO;
|
||||
#endif
|
||||
} else {
|
||||
const int nLen = topSegment.virtualLength();
|
||||
|
||||
@@ -741,7 +741,21 @@ function populateSegments(s)
|
||||
let segp = `<div id="segp${i}" class="sbs">`+
|
||||
`<i class="icons slider-icon pwr ${inst.on ? "act":""}" id="seg${i}pwr" title="Power" onclick="setSegPwr(${i})"></i>`+
|
||||
`<div class="sliderwrap il" title="Opacity/Brightness">`+
|
||||
`<input id="seg${i}bri" class="noslide" onchange="setSegBri(${i})" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" />`+
|
||||
`<input id="seg${i}bri" class="noslide" onchange="setSegProp(${i},'bri')" oninput="updateTrail(this)" max="255" min="1" type="range" value="${inst.bri}" />`+
|
||||
`<div class="sliderdisplay"></div>`+
|
||||
`</div>`+
|
||||
`</div>`;
|
||||
let zoom = `<div id="segzm${i}" class="lbl-l">`+
|
||||
`Zoom<br>`+
|
||||
`<div class="sliderwrap il" title="Zoom amount">`+
|
||||
`<input id="seg${i}zA" class="noslide" onchange="setSegProp(${i},'zA')" oninput="updateTrail(this)" max="15" min="0" type="range" value="${inst.zA}" />`+
|
||||
`<div class="sliderdisplay"></div>`+
|
||||
`</div>`+
|
||||
`</div>`;
|
||||
let rotate =`<div id="segrt${i}" class="lbl-l">`+
|
||||
`Rotation<br>`+
|
||||
`<div class="sliderwrap il" title="Rotation speed">`+
|
||||
`<input id="seg${i}rS" class="noslide" onchange="setSegProp(${i},'rS')" oninput="updateTrail(this)" max="15" min="0" type="range" value="${inst.rS}" />`+
|
||||
`<div class="sliderdisplay"></div>`+
|
||||
`</div>`+
|
||||
`</div>`;
|
||||
@@ -750,16 +764,16 @@ function populateSegments(s)
|
||||
let staY = inst.startY;
|
||||
let stoY = inst.stopY;
|
||||
let isMSeg = isM && staX<mw*mh; // 2D matrix segment
|
||||
let rvXck = `<label class="check revchkl">Reverse ${isM?'':'direction'}<input type="checkbox" id="seg${i}rev" onchange="setRev(${i})" ${inst.rev?"checked":""}><span class="checkmark"></span></label>`;
|
||||
let miXck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mi" onchange="setMi(${i})" ${inst.mi?"checked":""}><span class="checkmark"></span></label>`;
|
||||
let rvXck = `<label class="check revchkl">Reverse ${isM?'':'direction'}<input type="checkbox" id="seg${i}rev" onchange="setSegProp(${i},'rev')" ${inst.rev?"checked":""}><span class="checkmark"></span></label>`;
|
||||
let miXck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mi" onchange="setSegProp(${i},'mi')" ${inst.mi?"checked":""}><span class="checkmark"></span></label>`;
|
||||
let rvYck = "", miYck ="";
|
||||
let smpl = simplifiedUI ? 'hide' : '';
|
||||
if (isMSeg) {
|
||||
rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setRevY(${i})" ${inst.rY?"checked":""}><span class="checkmark"></span></label>`;
|
||||
miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setMiY(${i})" ${inst.mY?"checked":""}><span class="checkmark"></span></label>`;
|
||||
rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setSegProp(${i},'rY')" ${inst.rY?"checked":""}><span class="checkmark"></span></label>`;
|
||||
miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setSegProp(${i},'mY')" ${inst.mY?"checked":""}><span class="checkmark"></span></label>`;
|
||||
}
|
||||
let map2D = `<div id="seg${i}map2D" data-map="map2D" class="lbl-s hide">Expand 1D FX<br>`+
|
||||
`<div class="sel-p"><select class="sel-p" id="seg${i}m12" onchange="setM12(${i})">`+
|
||||
let map2D = `<div id="seg${i}map2D" data-map="map2D" data-fx="${inst.fx}" class="lbl-s hide">Expand 1D FX<br>`+
|
||||
`<div class="sel-p"><select class="sel-p" id="seg${i}m12" onchange="setSegProp(${i},'m12')">`+
|
||||
`<option value="0" ${inst.m12==0?' selected':''}>Pixels</option>`+
|
||||
`<option value="1" ${inst.m12==1?' selected':''}>Bar</option>`+
|
||||
`<option value="2" ${inst.m12==2?' selected':''}>Arc</option>`+
|
||||
@@ -768,7 +782,7 @@ function populateSegments(s)
|
||||
`</select></div>`+
|
||||
`</div>`;
|
||||
let blend = `<div class="lbl-l">Blend mode<br>`+
|
||||
`<div class="sel-p"><select class="sel-ple" id="seg${i}bm" onchange="setBm(${i})">`+
|
||||
`<div class="sel-p"><select class="sel-ple" id="seg${i}bm" onchange="setSegProp(${i},'bm')">`+
|
||||
`<option value="0" ${inst.bm==0?' selected':''}>Top/Default</option>`+
|
||||
`<option value="1" ${inst.bm==1?' selected':''}>Bottom/None</option>`+
|
||||
`<option value="2" ${inst.bm==2?' selected':''}>Add</option>`+
|
||||
@@ -788,7 +802,7 @@ function populateSegments(s)
|
||||
`</select></div>`+
|
||||
`</div>`;
|
||||
let sndSim = `<div data-snd="si" class="lbl-s hide">Sound sim<br>`+
|
||||
`<div class="sel-p"><select class="sel-p" id="seg${i}si" onchange="setSi(${i})">`+
|
||||
`<div class="sel-p"><select class="sel-p" id="seg${i}si" onchange="setSegProp(${i},'si')">`+
|
||||
`<option value="0" ${inst.si==0?' selected':''}>BeatSin</option>`+
|
||||
`<option value="1" ${inst.si==1?' selected':''}>WeWillRockYou</option>`+
|
||||
`<option value="2" ${inst.si==2?' selected':''}>10/13</option>`+
|
||||
@@ -844,12 +858,14 @@ function populateSegments(s)
|
||||
`<div class="h bp" id="seg${i}len"></div>`+
|
||||
blend +
|
||||
(!isMSeg ? rvXck : '') +
|
||||
(isMSeg?zoom:'')+
|
||||
(isMSeg?rotate:'')+
|
||||
(isMSeg&&stoY-staY>1&&stoX-staX>1 ? map2D : '') +
|
||||
(s.AudioReactive && s.AudioReactive.on ? "" : sndSim) +
|
||||
`<label class="check revchkl" id="seg${i}lbtm">`+
|
||||
(isMSeg?'Transpose':'Mirror effect') + (isMSeg ?
|
||||
'<input type="checkbox" id="seg'+i+'tp" onchange="setTp('+i+')" '+(inst.tp?"checked":"")+'>':
|
||||
'<input type="checkbox" id="seg'+i+'mi" onchange="setMi('+i+')" '+(inst.mi?"checked":"")+'>') +
|
||||
'<input type="checkbox" id="seg'+i+'tp" onchange="setSegProp('+i+',\'tp\')" '+(inst.tp?"checked":"")+'>':
|
||||
'<input type="checkbox" id="seg'+i+'mi" onchange="setSegProp('+i+',\'mi\')" '+(inst.mi?"checked":"")+'>') +
|
||||
`<span class="checkmark"></span>`+
|
||||
`</label>`+
|
||||
`<div class="del">`+
|
||||
@@ -870,6 +886,8 @@ function populateSegments(s)
|
||||
if (!gId(`seg${i}`)) continue;
|
||||
updateLen(i);
|
||||
updateTrail(gId(`seg${i}bri`));
|
||||
let r = gId(`seg${i}rS`); if (r) updateTrail(r);
|
||||
let z = gId(`seg${i}zA`); if (z) updateTrail(z);
|
||||
gId(`segr${i}`).classList.add("hide");
|
||||
}
|
||||
if (segCount < 2) {
|
||||
@@ -2265,6 +2283,14 @@ function delSeg(s)
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function setSegProp(s,p)
|
||||
{
|
||||
let o = gId(`seg${s}${p}`);
|
||||
let val = o.type === "checkbox" ? o.checked : parseInt(o.value);
|
||||
var obj = {"seg": {"id": s, [p]: val}};
|
||||
requestJson(obj);
|
||||
}
|
||||
/*
|
||||
function setRev(s)
|
||||
{
|
||||
var rev = gId(`seg${s}rev`).checked;
|
||||
@@ -2320,7 +2346,7 @@ function setTp(s)
|
||||
var obj = {"seg": {"id": s, "tp": tp}};
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
*/
|
||||
function setGrp(s, g)
|
||||
{
|
||||
event.preventDefault();
|
||||
@@ -2328,20 +2354,32 @@ function setGrp(s, g)
|
||||
var obj = {"seg": {"id": s, "set": g}};
|
||||
requestJson(obj);
|
||||
}
|
||||
/*
|
||||
function setZoom(s)
|
||||
{
|
||||
var obj = {"seg": {"id": s, "zA": parseInt(gId(`seg${s}za`).value)}};
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
function setRotation(s)
|
||||
{
|
||||
var obj = {"seg": {"id": s, "rS": parseInt(gId(`seg${s}rs`).value)}};
|
||||
requestJson(obj);
|
||||
}
|
||||
*/
|
||||
function setSegPwr(s)
|
||||
{
|
||||
var pwr = gId(`seg${s}pwr`).classList.contains('act');
|
||||
var obj = {"seg": {"id": s, "on": !pwr}};
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
/*
|
||||
function setSegBri(s)
|
||||
{
|
||||
var obj = {"seg": {"id": s, "bri": parseInt(gId(`seg${s}bri`).value)}};
|
||||
requestJson(obj);
|
||||
}
|
||||
|
||||
*/
|
||||
function tglFreeze(s=null)
|
||||
{
|
||||
var obj = {"seg": {"frz": "t"}}; // toggle
|
||||
|
||||
@@ -35,6 +35,9 @@ namespace {
|
||||
bool check1;
|
||||
bool check2;
|
||||
bool check3;
|
||||
uint8_t blendMode;
|
||||
uint8_t zoomAmount;
|
||||
uint8_t rotateSpeed;
|
||||
} SegmentCopy;
|
||||
|
||||
uint8_t differs(const Segment& b, const SegmentCopy& a) {
|
||||
@@ -57,6 +60,9 @@ namespace {
|
||||
if (a.check3 != b.check3) d |= SEG_DIFFERS_FX;
|
||||
if (a.startY != b.startY) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (a.stopY != b.stopY) d |= SEG_DIFFERS_BOUNDS;
|
||||
if (a.blendMode != b.blendMode) d |= SEG_DIFFERS_OPT;
|
||||
if (a.zoomAmount != b.zoomAmount) d |= SEG_DIFFERS_OPT;
|
||||
if (a.rotateSpeed != b.rotateSpeed) d |= SEG_DIFFERS_OPT;
|
||||
|
||||
//bit pattern: (msb first)
|
||||
// set:2, sound:2, mapping:3, transposed, mirrorY, reverseY, [reset,] paused, mirrored, on, reverse, [selected]
|
||||
@@ -108,7 +114,10 @@ static bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0)
|
||||
seg.custom3,
|
||||
seg.check1,
|
||||
seg.check2,
|
||||
seg.check3
|
||||
seg.check3,
|
||||
seg.blendMode,
|
||||
seg.zoomAmount,
|
||||
seg.rotateSpeed
|
||||
};
|
||||
|
||||
int start = elem["start"] | seg.start;
|
||||
@@ -152,6 +161,8 @@ static bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0)
|
||||
uint16_t spc = elem[F("spc")] | seg.spacing;
|
||||
uint16_t of = seg.offset;
|
||||
uint8_t soundSim = elem["si"] | seg.soundSim;
|
||||
uint8_t rotateSpeed = elem["rS"] | seg.rotateSpeed;
|
||||
uint8_t zoomAmount = elem["zA"] | seg.zoomAmount;
|
||||
uint8_t map1D2D = elem["m12"] | seg.map1D2D;
|
||||
uint8_t set = elem[F("set")] | seg.set;
|
||||
bool selected = getBoolVal(elem["sel"], seg.selected);
|
||||
@@ -269,6 +280,8 @@ static bool deserializeSegment(JsonObject elem, byte it, byte presetId = 0)
|
||||
}
|
||||
#endif
|
||||
|
||||
seg.rotateSpeed = constrain(rotateSpeed, 0, 15);
|
||||
seg.zoomAmount = constrain(zoomAmount, 0, 15);
|
||||
seg.set = constrain(set, 0, 3);
|
||||
seg.soundSim = constrain(soundSim, 0, 3);
|
||||
seg.selected = selected;
|
||||
@@ -631,6 +644,8 @@ static void serializeSegment(JsonObject& root, const Segment& seg, byte id, bool
|
||||
root["si"] = seg.soundSim;
|
||||
root["m12"] = seg.map1D2D;
|
||||
root["bm"] = seg.blendMode;
|
||||
root["rS"] = seg.rotateSpeed;
|
||||
root["zA"] = seg.zoomAmount;
|
||||
}
|
||||
|
||||
void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segmentBounds, bool selectedSegmentsOnly)
|
||||
|
||||
Reference in New Issue
Block a user