Update. Partytime!

This commit is contained in:
Kai Vogelgesang 2021-11-13 14:10:03 +01:00
parent 13baa93aff
commit c5f8aba5e0
Signed by: kai
GPG Key ID: 0A95D3B6E62C0879
6 changed files with 170 additions and 56 deletions

View File

@ -2,12 +2,13 @@
import { ipcMain } from 'electron';
import { blackout } from '../patterns/blackout';
import { Pattern, PatternOutput, RenderUpdate } from '../patterns/proto';
import { TestPattern } from '../patterns/test';
// import { TestPattern } from '../patterns/test';
import rust, { BeatTrackerHandle, MovingHeadState, OutputHandle, TrackerConfig } from 'rust_native_module';
import { ChaserPattern } from '../patterns/chaser';
import { HSLRandomMovementPattern } from '../patterns/hslRandom';
import { HSLRandomMovementPairsPattern } from '../patterns/hslRandom2';
import { SnoopDoggPattern } from '../patterns/snoop';
import { StroboInsGesichtPattern } from '../patterns/stroboInsGesichtLol';
export type AppState = {
patterns: { [key: string]: PatternOutput },
@ -62,11 +63,12 @@ class Backend {
// patterns
this.patterns = new Map();
this.patterns.set("test", new TestPattern());
this.patterns.set("chaser", new ChaserPattern());
// this.patterns.set("test", new TestPattern());
this.patterns.set("hslRandom", new HSLRandomMovementPattern());
this.patterns.set("snoop", new SnoopDoggPattern());
this.patterns.set("hslRandomPairs", new HSLRandomMovementPairsPattern());
this.patterns.set("chaser", new ChaserPattern());
this.patterns.set("snoop", new SnoopDoggPattern());
this.patterns.set("stroboInsGesictLOL", new StroboInsGesichtPattern());
this.state = {
patterns: {},
@ -142,8 +144,19 @@ class Backend {
let patternOutput = pattern.render(update);
this.state.patterns[patternId] = patternOutput;
if (patternId === this.state.selectedPattern && patternOutput) {
if (patternId === this.state.selectedPattern) {
if (patternOutput) {
output = patternOutput;
} else {
let choices = [
'hslRandom',
'hslRandomPairs',
];
this.state.selectedPattern = choices[Math.floor(Math.random() * choices.length)]
}
}
}

View File

@ -1,42 +1,77 @@
import { MovingHeadState } from 'rust_native_module';
import { Pattern, PatternOutput, RenderUpdate } from './proto';
import { TARGETS } from './stroboInsGesichtLol';
import { startAddresses } from './stage';
import { hsl2rgb, rescale } from './util';
import { Tuple4 } from './types';
const template: MovingHeadState = {
startAddress: 0,
pan: 0,
tilt: 0,
brightness: {
type: 'dimmer',
value: 0.2,
},
rgbw: [255, 0, 0, 0],
speed: 1,
reset: false,
}
export class ChaserPattern implements Pattern {
lastUpdate: number;
rgbw: Tuple4<number>;
constructor() {
this.lastUpdate = -8;
this.rgbw = [0, 0, 0, 255];
}
render(update: RenderUpdate): PatternOutput {
if (update.beatRelative === null) {
this.lastUpdate = -8;
return null;
}
let t = update.beatRelative;
if (t - this.lastUpdate > 4) {
this.lastUpdate = Math.floor(t);
if (Math.random() > 0.2) {
const h = rescale(Math.random(), { to: [0, 360] });
const s = 1;
const l = 0.5;
const [r, g, b] = hsl2rgb(h, s, l);
this.rgbw = [
Math.round(r * 255),
Math.round(g * 255),
Math.round(b * 255),
0
]
} else {
this.rgbw = [
0, 0, 0, 255
];
}
}
let head_number = Math.floor(t % 4);
let result: Tuple4<MovingHeadState> = [{ ...template }, { ...template }, { ...template }, { ...template }];
return startAddresses.map((address, index) => {
const [pan, tilt] = TARGETS[index];
[1, 15, 29, 43].forEach((startAddress, i) => {
result[i].startAddress = startAddress;
if (i === head_number) {
result[i].brightness = { type: 'dimmer', value: 1 };
const state: MovingHeadState = {
startAddress: address,
pan: pan,
tilt: tilt,
brightness: {
type: 'dimmer',
value: 0.1,
},
rgbw: this.rgbw,
speed: 1,
reset: false
}
});
return result;
if (index === head_number) {
state.brightness = { type: 'dimmer', value: 0.6 };
}
return state;
}) as PatternOutput;
}
}

View File

@ -0,0 +1,35 @@
import { MovingHeadState } from "rust_native_module";
import { Pattern, PatternOutput, RenderUpdate } from "./proto";
import { left, right, panForward, startAddresses, tiltUp, down } from "./stage";
import { Tuple4 } from "./types";
export const TARGETS: Tuple4<[number, number]> = [
[panForward + Math.atan(1) * left, tiltUp + Math.atan(1 / 3) * down],
[panForward + Math.atan(1 / 3) * left, tiltUp + Math.atan(1 / 3) * down],
[panForward + Math.atan(1 / 3) * right, tiltUp + Math.atan(1 / 3) * down],
[panForward + Math.atan(1) * right, tiltUp + Math.atan(1 / 3) * down],
]
export class StroboInsGesichtPattern implements Pattern {
render(_update: RenderUpdate): PatternOutput {
return startAddresses.map(((address, index) => {
const [pan, tilt] = TARGETS[index];
const state: MovingHeadState = {
startAddress: address,
pan: pan,
tilt: tilt,
brightness: {
type: "strobe",
value: 1,
},
rgbw: [0, 0, 0, 255],
speed: 1,
reset: false
}
return state;
})) as PatternOutput
}
}

View File

@ -1,14 +1,14 @@
import { MemoryRouter as Router, Switch, Route } from 'react-router-dom';
import { IpcRenderer } from 'electron/renderer';
import './App.css';
import { useEffect, useState } from 'react';
import { MemoryRouter as Router, Route, Switch } from 'react-router-dom';
import { AppState } from '../main/backend';
import PatternPreview from './PatternPreview';
import GraphVisualization from './Graph';
import ConfigControls from './ConfigControls';
import './App.css';
import { BongoCat } from './BongoCat';
import ConfigControls from './ConfigControls';
import GraphVisualization from './Graph';
import PatternPreview from './PatternPreview';
const ipcRenderer = (window as any).electron.ipcRenderer as IpcRenderer;
@ -50,7 +50,7 @@ const Frontend: React.FC<{ state: AppState }> = ({ state }) => {
<div style={{ width: "80%", marginTop: 80 }} className="element-row">
{
Object.entries(state.patterns).map(([patternId, output]) => (
<PatternPreview selected={state.selectedPattern === patternId} key={patternId} patternId={patternId} output={output} />
<PatternPreview selectedPattern={state.selectedPattern ?? ""} key={patternId} patternId={patternId} output={output} />
))
}
</div>

View File

@ -1,21 +1,52 @@
import { IpcRenderer } from "electron/renderer";
import { useState } from "react";
import { PatternOutput } from "../patterns/proto";
import './patterns.css';
import _snoop from '../res/snoop.png';
import _strobo from '../res/strobo.jpg';
const ipcRenderer = (window as any).electron.ipcRenderer as IpcRenderer;
const PatternPreview: React.FC<{ patternId: string, output: PatternOutput , selected: boolean}> = ({ patternId, output, selected}) => {
const PatternPreview: React.FC<{ patternId: string, output: PatternOutput, selectedPattern: string }> = ({ patternId, output, selectedPattern }) => {
const [previousPattern, setPreviousPattern] = useState(patternId);
const selected = selectedPattern === patternId;
const selectedClass = selected ? " selected" : "";
const styleClass = "pattern-button" + selectedClass;
const styleObj: React.CSSProperties = {};
if (patternId === "snoop") {
styleObj.background = "none";
}
return <div style={{ margin: 5 }}>
<svg className={styleClass}/*style={{ padding: 15, backgroundColor: "#333333", borderColor: "white", borderRadius: 15 }}*/ onClick={() =>
<svg className={styleClass}
style={styleObj}
onMouseUp={() => {
console.log("umu on", patternId);
if (patternId === "stroboInsGesictLOL") {
// restore after strobe
ipcRenderer.send("pattern-select", previousPattern);
}
}}
onMouseDown={() => {
console.log("omd on", patternId);
console.log("storing", selectedPattern);
// store before strobe
setPreviousPattern(selectedPattern);
ipcRenderer.send("pattern-select", patternId)
} width={260 + 2*70} height="150">
}}
//onClick={() =>
// ipcRenderer.send("pattern-select", patternId)
//}
width={260 + 2 * 70} height="150">
{output?.map((headState, index) => {
const [r, g, b, w] = headState.rgbw;
const brightness = "value" in headState.brightness ? headState.brightness.value : 0;
return <ColorCone tilt={headState.tilt} pan={headState.pan} white={w} color={`rgba(${r},${g},${b},${(0.3 + 0.7 * brightness)})`} translate={[70 + index * 65, 0]} />
return <ColorCone key={index} tilt={headState.tilt} pan={headState.pan} white={w} color={`rgba(${r},${g},${b},${(0.3 + 0.7 * brightness)})`} translate={[70 + index * 65, 0]} />
}
)}
</svg>

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB