update helpers/location to 'frosted' ui
[carveJwlIkooP6JGAAIwe30JlM.git] / particle.c
1 #include "vg/vg_lines.h"
2 #include "vg/vg_async.h"
3 #include "particle.h"
4 #include "shaders/particle.h"
5
6 struct particle_system particles_grind = {
7 .scale = 0.02f,
8 .velocity_scale = 0.001f,
9 .width = 0.0125f
10 },
11 particles_env = {
12 .scale = 0.04f,
13 .velocity_scale = 0.001f,
14 .width = 0.25f
15 };
16
17 void particle_spawn( particle_system *sys, v3f co, v3f v,
18 f32 lifetime, u32 colour )
19 {
20 if( sys->alive == sys->max ) return;
21
22 particle *p = &sys->array[ sys->alive ++ ];
23 v3_copy( co, p->co );
24 v3_copy( v, p->v );
25 p->life = lifetime;
26 p->colour = colour;
27 }
28
29 void particle_spawn_cone( particle_system *sys,
30 v3f co, v3f dir, f32 angle, f32 speed,
31 f32 lifetime, u32 colour )
32 {
33 if( sys->alive == sys->max ) return;
34
35 particle *p = &sys->array[ sys->alive ++ ];
36
37 v3f tx, ty;
38 v3_tangent_basis( dir, tx, ty );
39
40 v3f rand;
41 vg_rand_cone( &vg.rand, rand, angle );
42 v3_muls( tx, rand[0]*speed, p->v );
43 v3_muladds( p->v, ty, rand[1]*speed, p->v );
44 v3_muladds( p->v, dir, rand[2]*speed, p->v );
45
46 p->life = lifetime;
47 p->colour = colour;
48 v3_copy( co, p->co );
49 }
50
51 void particle_system_update( particle_system *sys, f32 dt )
52 {
53 u32 i = 0;
54 iter: if( i == sys->alive ) return;
55
56 particle *p = &sys->array[i];
57 p->life -= dt;
58
59 if( p->life < 0.0f ){
60 *p = sys->array[ -- sys->alive ];
61 goto iter;
62 }
63
64 v3_muladds( p->co, p->v, dt, p->co );
65 p->v[1] += -9.8f * dt;
66
67 i ++;
68 goto iter;
69 }
70
71 void particle_system_debug( particle_system *sys )
72 {
73 for( u32 i=0; i<sys->alive; i ++ ){
74 particle *p = &sys->array[i];
75 v3f p1;
76 v3_muladds( p->co, p->v, 0.2f, p1 );
77 vg_line( p->co, p1, p->colour );
78 }
79 }
80
81 struct particle_init_args {
82 particle_system *sys;
83 u16 indices[];
84 };
85
86 static void async_particle_init( void *payload, u32 size ){
87 struct particle_init_args *args = payload;
88 particle_system *sys = args->sys;
89
90 glGenVertexArrays( 1, &sys->vao );
91 glGenBuffers( 1, &sys->vbo );
92 glGenBuffers( 1, &sys->ebo );
93 glBindVertexArray( sys->vao );
94
95 size_t stride = sizeof(particle_vert);
96
97 glBindBuffer( GL_ARRAY_BUFFER, sys->vbo );
98 glBufferData( GL_ARRAY_BUFFER, sys->max*stride*4, NULL, GL_DYNAMIC_DRAW );
99 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, sys->ebo );
100 glBufferData( GL_ELEMENT_ARRAY_BUFFER,
101 sys->max*sizeof(u16)*6, args->indices, GL_STATIC_DRAW );
102
103 /* 0: coordinates */
104 glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0 );
105 glEnableVertexAttribArray( 0 );
106
107 /* 3: colour */
108 glVertexAttribPointer( 1, 4, GL_UNSIGNED_BYTE, GL_TRUE,
109 stride, (void *)offsetof(particle_vert, colour) );
110 glEnableVertexAttribArray( 1 );
111
112 VG_CHECK_GL_ERR();
113 }
114
115 void particle_alloc( particle_system *sys, u32 max )
116 {
117 size_t stride = sizeof(particle_vert);
118
119 sys->max = max;
120 sys->array = vg_linear_alloc( vg_mem.rtmemory, max*sizeof(particle) );
121 sys->vertices = vg_linear_alloc( vg_mem.rtmemory, max*stride*4 );
122
123 vg_async_item *call =
124 vg_async_alloc( sizeof(particle_system *) + max*sizeof(u16)*6 );
125 struct particle_init_args *init = call->payload;
126 init->sys = sys;
127
128 for( u32 i=0; i<max; i ++ ){
129 init->indices[i*6+0] = i*4;
130 init->indices[i*6+1] = i*4+1;
131 init->indices[i*6+2] = i*4+2;
132 init->indices[i*6+3] = i*4;
133 init->indices[i*6+4] = i*4+2;
134 init->indices[i*6+5] = i*4+3;
135 }
136
137 vg_async_dispatch( call, async_particle_init );
138 }
139
140 void particle_system_prerender( particle_system *sys )
141 {
142 for( u32 i=0; i<sys->alive; i ++ ){
143 particle *p = &sys->array[i];
144 particle_vert *vs = &sys->vertices[i*4];
145
146 v3f v, right;
147 v3_copy( p->v, v );
148
149 f32 vm = v3_length( p->v );
150 v3_muls( v, 1.0f/vm, v );
151 v3_cross( v, (v3f){0,1,0}, right );
152
153 f32 l = (sys->scale+sys->velocity_scale*vm),
154 w = sys->width;
155
156 v3f p0, p1;
157 v3_muladds( p->co, p->v, l, p0 );
158 v3_muladds( p->co, p->v, -l, p1 );
159
160 v3_muladds( p0, right, w, vs[0].co );
161 v3_muladds( p1, right, w, vs[1].co );
162 v3_muladds( p1, right, -w, vs[2].co );
163 v3_muladds( p0, right, -w, vs[3].co );
164
165 vs[0].colour = p->colour;
166 vs[1].colour = p->colour;
167 vs[2].colour = p->colour;
168 vs[3].colour = p->colour;
169 }
170
171 glBindVertexArray( sys->vao );
172
173 size_t stride = sizeof(particle_vert);
174 glBindBuffer( GL_ARRAY_BUFFER, sys->vbo );
175 glBufferSubData( GL_ARRAY_BUFFER, 0, sys->alive*stride*4, sys->vertices );
176 }
177
178 void particle_system_render( particle_system *sys, vg_camera *cam )
179 {
180 glDisable( GL_CULL_FACE );
181 glEnable( GL_DEPTH_TEST );
182
183 shader_particle_use();
184 shader_particle_uPv( cam->mtx.pv );
185 shader_particle_uPvPrev( cam->mtx_prev.pv );
186
187 glBindVertexArray( sys->vao );
188 glDrawElements( GL_TRIANGLES, sys->alive*6, GL_UNSIGNED_SHORT, NULL );
189 }