-
Notifications
You must be signed in to change notification settings - Fork 65
/
sim_fountain.go
146 lines (116 loc) · 3.08 KB
/
sim_fountain.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package effect
import (
"korok.io/korok/math/f32"
"korok.io/korok/gfx"
"korok.io/korok/math"
)
// FireSimulator can simulate the fire effect.
type FountainSimulator struct {
Pool
RateController
LifeController
VisualController
velocity Channel_v2
deltaColor Channel_v4
deltaRot Channel_f32
// Configuration.
Config struct{
Duration, Rate float32
Life Var
Size Var
Color TwoColor
Fading bool
Position [2]Var
Angle Var
Speed Var
Gravity float32
Rotation Var
Additive bool
}
}
func NewFountainSimulator(cap int) *FountainSimulator {
sim := FountainSimulator{Pool: Pool{Cap: cap}}
sim.AddChan(Life, Size)
sim.AddChan(Position, Velocity)
sim.AddChan(Color, ColorDelta)
sim.AddChan(Rotation, RotationDelta)
// config
sim.Config.Duration = math.MaxFloat32
sim.Config.Rate = float32(cap)/3
sim.Config.Life = Var{3, .25}
sim.Config.Color = TwoColor{f32.Vec4{1, 1, 1, 1}, f32.Vec4{1, 1, 1, 1}, false}
sim.Config.Fading = false
sim.Config.Size = Var{8, 2}
sim.Config.Angle = Var{3.14/2, 3.14/3}
sim.Config.Speed = Var{120, 20}
sim.Config.Rotation = Var{0, 1}
sim.Config.Gravity = -120
return &sim
}
func (f *FountainSimulator) Initialize() {
f.Pool.Initialize()
f.Life = f.Field(Life).(Channel_f32)
f.ParticleSize = f.Field(Size).(Channel_f32)
f.Position = f.Field(Position).(Channel_v2)
f.velocity = f.Field(Velocity).(Channel_v2)
f.Color = f.Field(Color).(Channel_v4)
f.deltaColor = f.Field(ColorDelta).(Channel_v4)
f.Rotation = f.Field(Rotation).(Channel_f32)
f.deltaRot = f.Field(RotationDelta).(Channel_f32)
f.RateController.Initialize(f.Config.Duration, f.Config.Rate)
}
func (f *FountainSimulator) Simulate(dt float32) {
// spawn new particle
if new := f.Rate(dt); new > 0 {
f.newParticle(new)
}
n := int32(f.Live)
// update old particle
f.Life.Sub(n, dt)
// position integrate: p' = p + v * t
f.Position.Integrate(n, f.velocity, dt)
// v' = v + g * t
f.velocity.Add(n, 0, f.Config.Gravity*dt)
// spin
f.Rotation.Integrate(n, f.deltaRot, dt)
// Color
f.Color.Integrate(n, f.deltaColor, dt)
// GC
f.GC(&f.Pool)
}
func (f *FountainSimulator) Size() (live, cap int) {
return int(f.Live), f.Cap
}
func (f *FountainSimulator) newParticle(new int) {
if (f.Live + new) > f.Cap {
return
}
start := f.Live
f.Live += new
for i := start; i < f.Live; i++ {
f.Life[i] = f.Config.Life.Random()
f.ParticleSize[i] = f.Config.Size.Random()
startColor := f.Config.Color.Random()
f.Color[i] = startColor
if f.Config.Fading {
invLife := 1/f.Life[i]
f.deltaColor[i] = f32.Vec4{
-startColor[0] * invLife,
-startColor[1] * invLife,
-startColor[2] * invLife,
-startColor[2] * invLife,
}
}
px := f.Config.Position[0].Random()
py := f.Config.Position[1].Random()
f.Position[i] = f32.Vec2{px, py}
a := f.Config.Angle.Random()
s := f.Config.Speed.Random()
f.velocity[i] = f32.Vec2{math.Cos(a)*s, math.Sin(a)*s}
r := f.Config.Rotation.Random()
f.deltaRot[i] = r
}
}
func (f *FountainSimulator) Visualize(buf []gfx.PosTexColorVertex, tex gfx.Tex2D) {
f.VisualController.Visualize(buf, tex, f.Live, f.Config.Additive)
}