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