Commit | Line | Data |
---|---|---|
20e7c94f VS |
1 | class VSTowers extends SCPattern { |
2 | private BasicParameter saturationParameter = new BasicParameter("SAT", 80, 0, 100); | |
3 | private BasicParameter attackParameter = new BasicParameter("ATTK", 0.96, 0.1, 1.0); | |
4 | private BasicParameter decayParameter = new BasicParameter("DECAY", 0.7, 0.1, 1.0); | |
5 | private SawLFO hueLfo = new SawLFO(0, 360, 20000); | |
6 | ||
7 | private Map<Tower, Boolean> towerOn; | |
8 | ||
9 | class TowerFlash { | |
10 | Tower t; | |
11 | float value; | |
12 | float maxVal; | |
13 | float hue; | |
14 | boolean hasPeaked; | |
15 | ||
16 | TowerFlash() { | |
17 | do { | |
18 | t = model.towers.get(floor(random(model.towers.size()))); | |
19 | } while (towerOn.get(t)); | |
20 | towerOn.put(t, true); | |
21 | hue = (hueLfo.getValuef() + 50*(random(2)-1.0f)) % 360; | |
22 | value = 0.0; | |
23 | maxVal = random(0.4) + 0.6; | |
24 | } | |
25 | ||
26 | boolean run(double deltaMs) { | |
27 | if (!hasPeaked) { | |
28 | float atk = attackParameter.getValuef(); | |
29 | float atkDuration = 10000 * (1/sqrt(atk) - 1.0f); | |
30 | value = value + (float)deltaMs / atkDuration; | |
31 | if (value >= maxVal) { | |
32 | value = maxVal; | |
33 | hasPeaked = true; | |
34 | } | |
35 | return false; | |
36 | } else { | |
37 | float dec = decayParameter.getValuef(); | |
38 | float decDuration = 10000 * (1/sqrt(dec) - 1.0f); | |
39 | value = value - (float)deltaMs / decDuration; | |
40 | return value <= 0; | |
41 | } | |
42 | } | |
43 | } | |
44 | ||
45 | public VSTowers(GLucose glucose) { | |
46 | super(glucose); | |
47 | addParameter(saturationParameter); | |
48 | addParameter(attackParameter); | |
49 | addParameter(decayParameter); | |
50 | addModulator(hueLfo).trigger(); | |
51 | flashes = new LinkedList<TowerFlash>(); | |
52 | towerOn = new HashMap(); | |
53 | for (Tower t : model.towers) { | |
54 | towerOn.put(t, false); | |
55 | } | |
56 | } | |
57 | ||
58 | private List<TowerFlash> flashes; | |
59 | private float accDelta = 0; | |
60 | ||
61 | public void run(double deltaMs) { | |
62 | accDelta += deltaMs; | |
63 | float rate = lx.tempo.rampf(); | |
64 | float msPerFlash = 5000 * (1/sqrt(rate) - 1.0f); | |
65 | if (accDelta >= msPerFlash) { | |
66 | accDelta -= msPerFlash; | |
67 | if (flashes.size() < model.towers.size()) { | |
68 | flashes.add(new TowerFlash()); | |
69 | } | |
70 | } | |
71 | for (LXPoint p : model.points) { | |
72 | if (random(1) < 0.2) { | |
73 | colors[p.index] = 0; | |
74 | } | |
75 | } | |
76 | for (TowerFlash tf : flashes) { | |
77 | for (LXPoint p : tf.t.points) { | |
78 | float towerHeight = model.yMin + tf.value * (model.yMax - model.yMin); | |
79 | if (p.y <= towerHeight) { | |
80 | colors[p.index] = lx.hsb( | |
81 | (tf.hue + tf.value*50 - p.y/2) % 360, | |
82 | saturationParameter.getValuef(), | |
83 | tf.value*100); | |
84 | } | |
85 | } | |
86 | if (tf.hasPeaked) { | |
87 | float towerMaxHeight = model.yMin + tf.maxVal * (model.yMax - model.yMin); | |
88 | Cube top = tf.t.cubes.get(tf.t.cubes.size()-1); | |
89 | for (int i = tf.t.cubes.size()-1; i >= 0; --i) { | |
90 | Cube c = tf.t.cubes.get(i); | |
91 | float maxY = c.points.get(0).y; | |
92 | for (LXPoint p : c.points) { | |
93 | maxY = max(maxY, p.y); | |
94 | } | |
95 | if (towerMaxHeight < maxY) { | |
96 | top = c; | |
97 | } | |
98 | } | |
99 | for (LXPoint p : top.points) { | |
100 | if (tf.value > 0.5) { | |
101 | colors[p.index] = lx.hsb(0, 0, tf.value*100); | |
102 | } else if (random(1) < 0.2) { | |
103 | colors[p.index] = 0; | |
104 | } | |
105 | } | |
106 | } | |
107 | } | |
108 | // Run flashes and remove completed ones | |
109 | Iterator<TowerFlash> it = flashes.iterator(); | |
110 | while (it.hasNext()) { | |
111 | TowerFlash flash = it.next(); | |
112 | if (flash.run(deltaMs)) { | |
113 | towerOn.put(flash.t, false); | |
114 | it.remove(); | |
115 | } | |
116 | } | |
117 | } | |
118 | } | |
119 |