javascript based particle system
This commit is contained in:
parent
ff71ee9db6
commit
d4b057dc6f
|
@ -512,6 +512,7 @@ global.mixin("scripts/color");
|
|||
global.mixin("scripts/gui");
|
||||
global.mixin("scripts/tween");
|
||||
global.mixin("scripts/ai");
|
||||
global.mixin("scripts/particle");
|
||||
|
||||
var timer = {
|
||||
update(dt) {
|
||||
|
|
|
@ -36,7 +36,6 @@ var entity = {
|
|||
rigidify() {
|
||||
this.body = os.make_body(this.transform);
|
||||
},
|
||||
|
||||
|
||||
path_from(o) {
|
||||
var p = this.toString();
|
||||
|
|
105
scripts/particle.js
Normal file
105
scripts/particle.js
Normal file
|
@ -0,0 +1,105 @@
|
|||
var emitter = {};
|
||||
emitter.particles = {};
|
||||
emitter.life = 10;
|
||||
emitter.scale = 1;
|
||||
emitter.grow_for = 0;
|
||||
emitter.spawn_timer = 0;
|
||||
emitter.pps = 0;
|
||||
emitter.color = Color.white;
|
||||
|
||||
emitter.draw = function()
|
||||
{
|
||||
var amt = Object.values(this.particles).length;
|
||||
if (amt === 0) return;
|
||||
render.use_shader(this.shader);
|
||||
render.use_mat(this);
|
||||
var ts = [];
|
||||
for (var p of Object.values(this.particles)) ts.push([p.transform,p.color]);
|
||||
render.make_particle_ssbo(ts, this.ssbo);
|
||||
render.draw(this.shape, this.ssbo, amt);
|
||||
}
|
||||
|
||||
var std_spawn = function(par)
|
||||
{
|
||||
}
|
||||
|
||||
var std_step = function(p)
|
||||
{
|
||||
if (p.time < this.grow_for) {
|
||||
var s = Math.lerp(0, this.scale, p.time/this.grow_for);
|
||||
p.transform.scale = [s,s,s];
|
||||
}
|
||||
else if (p.time > (p.life - this.shrink_for)) {
|
||||
var s = Math.lerp(0,this.scale,(p.life-p.time)/this.shrink_for);
|
||||
p.transform.scale=[s,s,s];
|
||||
} else
|
||||
p.transform.scale = [this.scale,this.scale,this.scale];
|
||||
}
|
||||
|
||||
var std_die = function(par)
|
||||
{
|
||||
}
|
||||
|
||||
emitter.spawn_hook = std_spawn;
|
||||
emitter.step_hook = std_step;
|
||||
emitter.die_hook = std_die;
|
||||
|
||||
emitter.spawn = function(t)
|
||||
{
|
||||
t ??= this.transform;
|
||||
var par = {
|
||||
transform: os.make_transform(),
|
||||
life: this.life,
|
||||
time: 0,
|
||||
color: this.color
|
||||
};
|
||||
|
||||
par.body = os.make_body(par.transform);
|
||||
|
||||
par.body.pos = t.pos;
|
||||
par.transform.scale = [this.scale,this.scale,this.scale];
|
||||
par.id = prosperon.guid();
|
||||
this.particles[par.id] = par;
|
||||
|
||||
this.spawn_hook(par);
|
||||
}
|
||||
|
||||
emitter.step = function(dt)
|
||||
{
|
||||
// update spawning particles
|
||||
if (this.on && this.pps > 0) {
|
||||
this.spawn_timer += dt;
|
||||
var pp = 1/this.pps;
|
||||
while (this.spawn_timer > pp) {
|
||||
this.spawn_timer -= pp;
|
||||
this.spawn();
|
||||
}
|
||||
}
|
||||
|
||||
// update all particles
|
||||
for (var p of Object.values(this.particles)) {
|
||||
p.time += dt;
|
||||
|
||||
this.step_hook(p);
|
||||
|
||||
if (p.time >= p.life) {
|
||||
this.die_hook(p);
|
||||
delete this.particles[p.id];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emitter.burst = function(count, t) {
|
||||
for (var i = 0; i < count; i++) this.spawn(t);
|
||||
}
|
||||
|
||||
var make_emitter = function()
|
||||
{
|
||||
var e = Object.create(emitter);
|
||||
e.ssbo = render.make_textssbo();
|
||||
e.shape = shape.quad;
|
||||
e.shader = render.make_shader("shaders/baseparticle.cg");
|
||||
return e;
|
||||
}
|
||||
|
||||
return {make_emitter};
|
|
@ -162,9 +162,13 @@ render.set_camera = function(cam)
|
|||
delete cur.shader;
|
||||
setcam(cam);
|
||||
}
|
||||
|
||||
var shader_cache = {};
|
||||
|
||||
render.make_shader = function(shader)
|
||||
{
|
||||
if (shader_cache[shader]) return shader_cache[shader];
|
||||
|
||||
var file = shader;
|
||||
shader = io.slurp(shader);
|
||||
if (!shader) {
|
||||
|
@ -188,6 +192,7 @@ render.make_shader = function(shader)
|
|||
var shaderobj = json.decode(io.slurp(writejson));
|
||||
var obj = shaderobj[os.sys()];
|
||||
obj.pipe = render.pipeline(obj);
|
||||
shader_cache[shader] = obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -304,6 +309,7 @@ render.make_shader = function(shader)
|
|||
var obj = compiled[os.sys()];
|
||||
obj.pipe = render.pipeline(obj);
|
||||
|
||||
shader_cache[shader] = obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -640,11 +646,14 @@ render.slice9 = function(tex, pos, bb, scale = [tex.width,tex.height], color = C
|
|||
|
||||
render.emitter = function(emit)
|
||||
{
|
||||
var amt = emit.draw();
|
||||
var amt = Object.values(emit.particles).length;
|
||||
if (amt === 0) return;
|
||||
render.use_shader(parshader);
|
||||
render.use_mat(emit);
|
||||
render.draw(shape.quad, emit.buffer, amt);
|
||||
var ts = [];
|
||||
for (var p of Object.values(emit.particles)) ts.push([p.transform,p.color]);
|
||||
render.make_particle_ssbo(ts, emit.ssbo);
|
||||
render.draw(shape.quad, emit.ssbo, amt);
|
||||
}
|
||||
|
||||
var textssbo;
|
||||
|
|
|
@ -8,9 +8,7 @@ in vec2 a_uv;
|
|||
uniform vec2 diffuse_size;
|
||||
|
||||
struct particle {
|
||||
vec2 pos;
|
||||
float angle;
|
||||
float scale;
|
||||
mat4 model;
|
||||
vec4 color;
|
||||
};
|
||||
|
||||
|
@ -28,21 +26,16 @@ void main()
|
|||
{
|
||||
particle p = par[gl_InstanceIndex];
|
||||
pos = a_pos - 0.5;
|
||||
vec2 rot = pos;
|
||||
rot.x = pos.x*cos(p.angle) - pos.y*sin(p.angle);
|
||||
rot.y = pos.x*sin(p.angle) + pos.y*cos(p.angle);
|
||||
pos = rot*p.scale;
|
||||
pos += p.pos;
|
||||
color0 = p.color;
|
||||
gl_Position = vp * vec4(pos, 0.0, 1.0);
|
||||
gl_Position = vp * p.model * vec4(pos, 0.0, 1.0);
|
||||
uv = a_pos;
|
||||
color0 = p.color;
|
||||
}
|
||||
@end
|
||||
|
||||
@fs fs
|
||||
in vec2 uv;
|
||||
in vec4 color0;
|
||||
|
||||
in vec4 color0;
|
||||
out vec4 color;
|
||||
|
||||
texture2D diffuse;
|
||||
|
@ -50,7 +43,7 @@ sampler smp;
|
|||
|
||||
void main()
|
||||
{
|
||||
color = texture(sampler2D(diffuse,smp), uv);
|
||||
color = texture(sampler2D(diffuse,smp),uv);
|
||||
color *= color0;
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -13,7 +13,6 @@ uniform vec4 shade;
|
|||
void frag()
|
||||
{
|
||||
color = texture(sampler2D(diffuse,smp), uv);
|
||||
if (color.a < 0.1) discard;
|
||||
color *= shade;
|
||||
}
|
||||
@end
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "window.h"
|
||||
#include "spline.h"
|
||||
#include "yugine.h"
|
||||
#include "particle.h"
|
||||
#include <assert.h>
|
||||
#include "resources.h"
|
||||
#include <sokol/sokol_time.h>
|
||||
|
@ -96,7 +95,6 @@ void cpConstraint_free(cpConstraint *c)
|
|||
void jsfreestr(const char *s) { JS_FreeCString(js, s); }
|
||||
QJSCLASS(gameobject)
|
||||
QJSCLASS(transform)
|
||||
QJSCLASS(emitter)
|
||||
QJSCLASS(dsp_node)
|
||||
QJSCLASS(texture)
|
||||
QJSCLASS(font)
|
||||
|
@ -661,34 +659,6 @@ sg_bindings js2bind(JSValue v)
|
|||
return bind;
|
||||
}
|
||||
|
||||
JSC_GETSET(emitter, life, number)
|
||||
JSC_GETSET(emitter, life_var, number)
|
||||
JSC_GETSET(emitter, speed, number)
|
||||
JSC_GETSET(emitter, variation, number)
|
||||
JSC_GETSET(emitter, divergence, number)
|
||||
JSC_GETSET(emitter, scale, number)
|
||||
JSC_GETSET(emitter, scale_var, number)
|
||||
JSC_GETSET(emitter, grow_for, number)
|
||||
JSC_GETSET(emitter, shrink_for, number)
|
||||
JSC_GETSET(emitter, color, vec4)
|
||||
JSC_GETSET(emitter, max, number)
|
||||
JSC_GETSET(emitter, explosiveness, number)
|
||||
JSC_GETSET(emitter, bounce, number)
|
||||
JSC_GETSET(emitter, collision_mask, bitmask)
|
||||
JSC_GETSET(emitter, die_after_collision, boolean)
|
||||
JSC_GETSET(emitter, tumble, number)
|
||||
JSC_GETSET(emitter, tumble_rate, number)
|
||||
JSC_GETSET(emitter, persist, number)
|
||||
JSC_GETSET(emitter, persist_var, number)
|
||||
JSC_GETSET(emitter, warp_mask, bitmask)
|
||||
JSC_CCALL(emitter_emit, emitter_emit(js2emitter(self), js2number(argv[0]), js2transform(argv[1])))
|
||||
JSC_CCALL(emitter_step, emitter_step(js2emitter(self), js2number(argv[0]), js2transform(argv[1])))
|
||||
JSC_CCALL(emitter_draw,
|
||||
sg_buffer *b = js2sg_buffer(js_getpropstr(self, "buffer"));
|
||||
emitter_draw(js2emitter(self), b);
|
||||
return number2js(arrlen(js2emitter(self)->verts));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_flushtext,
|
||||
sg_buffer *buf = js2sg_buffer(argv[0]);
|
||||
int amt = text_flush(buf);
|
||||
|
@ -968,24 +938,67 @@ JSC_CCALL(render_setbind,
|
|||
sg_apply_bindings(&bind);
|
||||
)
|
||||
|
||||
typedef struct particle_ss {
|
||||
HMM_Mat4 model;
|
||||
HMM_Vec4 color;
|
||||
} particle_ss;
|
||||
|
||||
JSC_CCALL(render_make_particle_ssbo,
|
||||
JSValue array = argv[0];
|
||||
size_t size = js_arrlen(array)*(sizeof(particle_ss));
|
||||
sg_buffer *b = js2sg_buffer(argv[1]);
|
||||
if (!b) return JS_UNDEFINED;
|
||||
|
||||
particle_ss ms[js_arrlen(array)];
|
||||
|
||||
if (sg_query_buffer_will_overflow(*b, size)) {
|
||||
sg_destroy_buffer(*b);
|
||||
*b = sg_make_buffer(&(sg_buffer_desc){
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.size = size,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "transform buffer"
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < js_arrlen(array); i++) {
|
||||
JSValue sub = js_getpropidx(array,i);
|
||||
ms[i].model = transform2mat(*js2transform(js_getpropidx(sub, 0)));
|
||||
ms[i].color = js2vec4(js_getpropidx(sub,1));
|
||||
}
|
||||
|
||||
sg_append_buffer(*b, (&(sg_range){
|
||||
.ptr = ms,
|
||||
.size = size
|
||||
}));
|
||||
|
||||
)
|
||||
|
||||
JSC_CCALL(render_make_t_ssbo,
|
||||
JSValue array = argv[0];
|
||||
size_t size = js_arrlen(array)*sizeof(HMM_Mat4);
|
||||
sg_buffer *b = js2sg_buffer(argv[1]);
|
||||
if (!b) return JS_UNDEFINED;
|
||||
|
||||
HMM_Mat4 ms[js_arrlen(array)];
|
||||
|
||||
if (sg_query_buffer_will_overflow(*b, size)) {
|
||||
sg_destroy_buffer(*b);
|
||||
*b = sg_make_buffer(&(sg_buffer_desc){
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.size = size,
|
||||
.usage = SG_USAGE_STREAM,
|
||||
.label = "transform buffer"
|
||||
});
|
||||
}
|
||||
|
||||
for (int i = 0; i < js_arrlen(array); i++)
|
||||
ms[i] = transform2mat(*js2transform(js_getpropidx(array, i)));
|
||||
|
||||
sg_buffer *rr = malloc(sizeof(sg_buffer));
|
||||
*rr = sg_make_buffer(&(sg_buffer_desc){
|
||||
.data = {
|
||||
.ptr = ms,
|
||||
.size = sizeof(HMM_Mat4)*js_arrlen(array),
|
||||
},
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.usage = SG_USAGE_IMMUTABLE,
|
||||
.label = "transform buffer"
|
||||
});
|
||||
|
||||
return sg_buffer2js(rr);
|
||||
sg_append_buffer(*b, (&(sg_range){
|
||||
.ptr = ms,
|
||||
.size = size
|
||||
}));
|
||||
)
|
||||
|
||||
JSC_CCALL(render_spdraw,
|
||||
|
@ -1037,7 +1050,8 @@ static const JSCFunctionListEntry js_render_funcs[] = {
|
|||
MIST_FUNC_DEF(render, gfx_gui, 0),
|
||||
MIST_FUNC_DEF(render, imgui_end, 0),
|
||||
MIST_FUNC_DEF(render, imgui_init, 0),
|
||||
MIST_FUNC_DEF(render, make_t_ssbo, 1)
|
||||
MIST_FUNC_DEF(render, make_t_ssbo, 2),
|
||||
MIST_FUNC_DEF(render, make_particle_ssbo, 2)
|
||||
};
|
||||
|
||||
JSC_CCALL(gui_scissor, sg_apply_scissor_rect(js2number(argv[0]), js2number(argv[1]), js2number(argv[2]), js2number(argv[3]), 0))
|
||||
|
@ -1484,32 +1498,6 @@ static const JSCFunctionListEntry js_physics_funcs[] = {
|
|||
CGETSET_ADD(physics, collision_persistence),
|
||||
};
|
||||
|
||||
static const JSCFunctionListEntry js_emitter_funcs[] = {
|
||||
CGETSET_ADD(emitter, life),
|
||||
CGETSET_ADD(emitter, life_var),
|
||||
CGETSET_ADD(emitter, speed),
|
||||
CGETSET_ADD(emitter, variation),
|
||||
CGETSET_ADD(emitter, divergence),
|
||||
CGETSET_ADD(emitter, scale),
|
||||
CGETSET_ADD(emitter, scale_var),
|
||||
CGETSET_ADD(emitter, grow_for),
|
||||
CGETSET_ADD(emitter, shrink_for),
|
||||
CGETSET_ADD(emitter, max),
|
||||
CGETSET_ADD(emitter, color),
|
||||
CGETSET_ADD(emitter, tumble),
|
||||
CGETSET_ADD(emitter, tumble_rate),
|
||||
CGETSET_ADD(emitter, explosiveness),
|
||||
CGETSET_ADD(emitter, bounce),
|
||||
CGETSET_ADD(emitter, collision_mask),
|
||||
CGETSET_ADD(emitter, die_after_collision),
|
||||
CGETSET_ADD(emitter, persist),
|
||||
CGETSET_ADD(emitter, persist_var),
|
||||
CGETSET_ADD(emitter, warp_mask),
|
||||
MIST_FUNC_DEF(emitter, emit, 1),
|
||||
MIST_FUNC_DEF(emitter, step, 1),
|
||||
MIST_FUNC_DEF(emitter, draw, 1)
|
||||
};
|
||||
|
||||
JSC_GETSET(transform, pos, vec3)
|
||||
JSC_GETSET(transform, scale, vec3)
|
||||
JSC_GETSET(transform, rotation, quat)
|
||||
|
@ -1543,10 +1531,21 @@ JSC_CCALL(transform_direction,
|
|||
return vec32js(HMM_QVRot(js2vec3(argv[0]), t->rotation));
|
||||
)
|
||||
|
||||
JSC_CCALL(transform_phys2d,
|
||||
transform *t = js2transform(self);
|
||||
HMM_Vec2 v = js2vec2(argv[0]);
|
||||
float av = js2number(argv[1]);
|
||||
float dt = js2number(argv[2]);
|
||||
transform_move(t, (HMM_Vec3){v.x*dt,v.y*dt,0});
|
||||
HMM_Quat rot = HMM_QFromAxisAngle_LH((HMM_Vec3){0,0,1}, av*dt);
|
||||
t->rotation = HMM_MulQ(t->rotation, rot);
|
||||
)
|
||||
|
||||
static const JSCFunctionListEntry js_transform_funcs[] = {
|
||||
CGETSET_ADD(transform, pos),
|
||||
CGETSET_ADD(transform, scale),
|
||||
CGETSET_ADD(transform, rotation),
|
||||
MIST_FUNC_DEF(transform, phys2d, 3),
|
||||
MIST_FUNC_DEF(transform, move, 1),
|
||||
MIST_FUNC_DEF(transform, rotate, 2),
|
||||
MIST_FUNC_DEF(transform, angle, 1),
|
||||
|
@ -2399,18 +2398,6 @@ JSC_SCALL(os_make_model,
|
|||
return v;
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_emitter,
|
||||
emitter *e = make_emitter();
|
||||
ret = emitter2js(e);
|
||||
sg_buffer *b = malloc(sizeof(*b));
|
||||
*b = sg_make_buffer(&(sg_buffer_desc) {
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.size = 4,
|
||||
.usage = SG_USAGE_STREAM
|
||||
});
|
||||
js_setpropstr(ret, "buffer", sg_buffer2js(b));
|
||||
)
|
||||
|
||||
JSC_CCALL(os_make_buffer,
|
||||
int type = js2number(argv[1]);
|
||||
float *b = malloc(sizeof(float)*js_arrlen(argv[0]));
|
||||
|
@ -2590,7 +2577,6 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||
MIST_FUNC_DEF(os, make_font, 2),
|
||||
MIST_FUNC_DEF(os, make_model, 1),
|
||||
MIST_FUNC_DEF(os, make_transform, 0),
|
||||
MIST_FUNC_DEF(os, make_emitter, 0),
|
||||
MIST_FUNC_DEF(os, make_buffer, 1),
|
||||
MIST_FUNC_DEF(os, make_line_prim, 4),
|
||||
MIST_FUNC_DEF(os, make_cylinder, 2),
|
||||
|
@ -2623,7 +2609,6 @@ void ffi_load() {
|
|||
QJSCLASSPREP_FUNCS(gameobject);
|
||||
QJSCLASSPREP_FUNCS(transform);
|
||||
QJSCLASSPREP_FUNCS(dsp_node);
|
||||
QJSCLASSPREP_FUNCS(emitter);
|
||||
QJSCLASSPREP_FUNCS(warp_gravity);
|
||||
QJSCLASSPREP_FUNCS(warp_damp);
|
||||
QJSCLASSPREP_FUNCS(texture);
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
#include "particle.h"
|
||||
#include "stb_ds.h"
|
||||
#include "render.h"
|
||||
#include "2dphysics.h"
|
||||
#include "math.h"
|
||||
#include "log.h"
|
||||
|
||||
emitter *make_emitter() {
|
||||
emitter *e = calloc(sizeof(*e),1);
|
||||
|
||||
e->max = 20;
|
||||
arrsetcap(e->particles, 10);
|
||||
for (int i = 0; i < arrlen(e->particles); i++)
|
||||
e->particles[i].life = 0;
|
||||
|
||||
e->life = 10;
|
||||
e->tte = lerp(e->explosiveness, e->life/e->max, 0);
|
||||
e->scale = 1;
|
||||
e->speed = 20;
|
||||
e->color = (HMM_Vec4){1,1,1,1};
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
void emitter_free(emitter *e)
|
||||
{
|
||||
arrfree(e->particles);
|
||||
arrfree(e->verts);
|
||||
free(e);
|
||||
}
|
||||
|
||||
/* Variate a value around variance. Variance between 0 and 1. */
|
||||
|
||||
float variate(float val, float variance)
|
||||
{
|
||||
return val + val*(frand(variance)-(variance/2));
|
||||
}
|
||||
|
||||
int emitter_spawn(emitter *e, transform *t)
|
||||
{
|
||||
if (arrlen(e->particles) == e->max) return 0;
|
||||
particle p = {0};
|
||||
p.life = e->life;
|
||||
p.pos = (HMM_Vec4){t->pos.x,t->pos.y,t->pos.z,0};
|
||||
HMM_Vec3 up = transform_direction(t, vFWD);
|
||||
float newan = (frand(e->divergence)-(e->divergence/2))*HMM_TurnToRad;
|
||||
HMM_Vec2 v2n = HMM_V2Rotate((HMM_Vec2){0,1}, newan);
|
||||
HMM_Vec3 norm = (HMM_Vec3){v2n.x, v2n.y,0};
|
||||
p.v = HMM_MulV4F((HMM_Vec4){norm.x,norm.y,norm.z,0}, variate(e->speed, e->variation));
|
||||
p.angle = e->tumble;
|
||||
p.av = e->tumble_rate;
|
||||
p.scale = variate(e->scale*t->scale.x, e->scale_var);
|
||||
arrput(e->particles,p);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void emitter_emit(emitter *e, int count, transform *t)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
emitter_spawn(e, t);
|
||||
}
|
||||
|
||||
void emitter_draw(emitter *e, sg_buffer *b)
|
||||
{
|
||||
if (arrlen(e->particles) == 0) return;
|
||||
arrsetlen(e->verts, arrlen(e->particles));
|
||||
for (int i = 0; i < arrlen(e->particles); i++) {
|
||||
if (e->particles[i].time >= e->particles[i].life) continue;
|
||||
particle *p = e->particles+i;
|
||||
e->verts[i].pos = p->pos.xy;
|
||||
e->verts[i].angle = p->angle;
|
||||
e->verts[i].scale = p->scale;
|
||||
if (p->time < e->grow_for)
|
||||
e->verts[i].scale = lerp(p->time/e->grow_for, 0, p->scale);
|
||||
else if (p->time > (p->life - e->shrink_for))
|
||||
e->verts[i].scale = lerp((p->time-(p->life-e->shrink_for))/e->shrink_for, p->scale, 0);
|
||||
e->verts[i].color = p->color;
|
||||
}
|
||||
|
||||
sg_range verts;
|
||||
verts.ptr = e->verts;
|
||||
verts.size = sizeof(*e->verts)*arrlen(e->verts);
|
||||
if (sg_query_buffer_will_overflow(*b, verts.size)) {
|
||||
sg_destroy_buffer(*b);
|
||||
*b = sg_make_buffer(&(sg_buffer_desc){
|
||||
.size = verts.size,
|
||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
||||
.usage = SG_USAGE_STREAM
|
||||
});
|
||||
}
|
||||
|
||||
sg_append_buffer(*b, &verts);
|
||||
}
|
||||
|
||||
void emitter_step(emitter *e, double dt, transform *t) {
|
||||
HMM_Vec4 g_accel = HMM_MulV4F((HMM_Vec4){cpSpaceGetGravity(space).x, cpSpaceGetGravity(space).y, 0, 0}, dt);
|
||||
|
||||
for (int i = 0; i < arrlen(e->particles); i++) {
|
||||
if (e->particles[i].time >= e->particles[i].life) continue;
|
||||
|
||||
if (e->warp_mask & gravmask)
|
||||
e->particles[i].v = HMM_AddV4(e->particles[i].v, g_accel);
|
||||
|
||||
e->particles[i].pos = HMM_AddV4(e->particles[i].pos, HMM_MulV4F(e->particles[i].v, dt));
|
||||
e->particles[i].angle += e->particles[i].av*dt;
|
||||
e->particles[i].time += dt;
|
||||
e->particles[i].color = e->color;
|
||||
//e->particles[i].color = sample_sampler(&e->color, e->particles[i].time/e->particles[i].life);
|
||||
e->particles[i].scale = e->scale;
|
||||
|
||||
if (e->particles[i].time >= e->particles[i].life)
|
||||
arrdelswap(e->particles, i);
|
||||
// else if (query_point(e->particles[i].pos.xy))
|
||||
// arrdelswap(e->particles,i);
|
||||
}
|
||||
|
||||
e->tte-=dt;
|
||||
float step = lerp(e->explosiveness, e->life/e->max,0);
|
||||
while (e->tte <= 0) {
|
||||
e->tte += step;
|
||||
if (!emitter_spawn(e, t)) break;
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
#ifndef PARTICLE_H
|
||||
#define PARTICLE_H
|
||||
|
||||
#include "HandmadeMath.h"
|
||||
#include "warp.h"
|
||||
#include "transform.h"
|
||||
#include "texture.h"
|
||||
#include "anim.h"
|
||||
#include "gameobject.h"
|
||||
#include "render.h"
|
||||
|
||||
typedef struct particle {
|
||||
HMM_Vec4 pos;
|
||||
HMM_Vec4 v; /* velocity */
|
||||
float angle;
|
||||
float av; /* angular velocity */
|
||||
float scale;
|
||||
double time;
|
||||
double life;
|
||||
HMM_Vec4 color;
|
||||
} particle;
|
||||
|
||||
#define SPRAY 0
|
||||
#define CLOUD 1
|
||||
#define MESH 2
|
||||
|
||||
typedef struct par_vert {
|
||||
HMM_Vec2 pos;
|
||||
float angle;
|
||||
float scale;
|
||||
HMM_Vec4 color;
|
||||
} par_vert;
|
||||
|
||||
typedef struct emitter {
|
||||
struct particle *particles;
|
||||
par_vert *verts;
|
||||
HMM_Vec3 *mesh; /* list of points to optionally spawn from */
|
||||
HMM_Vec3 *norm; /* norm at each point */
|
||||
int type; /* spray, cloud, or mesh */
|
||||
float explosiveness; /* 0 for a stream, 1 for all at once. Range of values allowed. */
|
||||
int max; /* number of particles */
|
||||
double life; /* how long a particle lasts */
|
||||
double life_var;
|
||||
/* SPRAY PARTICLE GEN */
|
||||
float speed; /* initial speed of particle */
|
||||
float variation; /* variation on speed */
|
||||
float divergence; /* angular degree of variation from emitter normal, up to 1 */
|
||||
float tumble; /* amount of random rotation of particles */
|
||||
float tumble_rate; /* tumble rotation */
|
||||
HMM_Vec4 color; /* color over particle lifetime */
|
||||
float scale;
|
||||
float scale_var;
|
||||
float grow_for; /* seconds to grow from small until scale */
|
||||
float shrink_for; /* seconds to shrink to small prior to its death */
|
||||
/* ROTATION AND COLLISION */
|
||||
int collision_mask; /* mask for collision */
|
||||
float bounce; /* bounce back after collision */
|
||||
/* PARTICLE SPAWN */
|
||||
int die_after_collision;
|
||||
float persist; /* how long to linger after death */
|
||||
float persist_var;
|
||||
/* TRAILS */
|
||||
warpmask warp_mask;
|
||||
double tte; /* time to emit */
|
||||
} emitter;
|
||||
|
||||
emitter *make_emitter();
|
||||
void emitter_free(emitter *e);
|
||||
|
||||
void emitter_emit(emitter *e, int count, transform *t);
|
||||
void emitter_step(emitter *e, double dt, transform *t);
|
||||
void emitter_draw(emitter *e, sg_buffer *b);
|
||||
|
||||
#endif
|
|
@ -5,7 +5,6 @@
|
|||
#include "font.h"
|
||||
#include "gameobject.h"
|
||||
#include "log.h"
|
||||
#include "particle.h"
|
||||
#include "window.h"
|
||||
#include "model.h"
|
||||
#include "stb_ds.h"
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "resources.h"
|
||||
#include "spline.h"
|
||||
#include <stdio.h>
|
||||
#include "particle.h"
|
||||
#include "simplex.h"
|
||||
#include <wctype.h>
|
||||
|
||||
|
|
Loading…
Reference in a new issue