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/gui");
|
||||||
global.mixin("scripts/tween");
|
global.mixin("scripts/tween");
|
||||||
global.mixin("scripts/ai");
|
global.mixin("scripts/ai");
|
||||||
|
global.mixin("scripts/particle");
|
||||||
|
|
||||||
var timer = {
|
var timer = {
|
||||||
update(dt) {
|
update(dt) {
|
||||||
|
|
|
@ -36,7 +36,6 @@ var entity = {
|
||||||
rigidify() {
|
rigidify() {
|
||||||
this.body = os.make_body(this.transform);
|
this.body = os.make_body(this.transform);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
path_from(o) {
|
path_from(o) {
|
||||||
var p = this.toString();
|
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;
|
delete cur.shader;
|
||||||
setcam(cam);
|
setcam(cam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var shader_cache = {};
|
||||||
|
|
||||||
render.make_shader = function(shader)
|
render.make_shader = function(shader)
|
||||||
{
|
{
|
||||||
|
if (shader_cache[shader]) return shader_cache[shader];
|
||||||
|
|
||||||
var file = shader;
|
var file = shader;
|
||||||
shader = io.slurp(shader);
|
shader = io.slurp(shader);
|
||||||
if (!shader) {
|
if (!shader) {
|
||||||
|
@ -188,6 +192,7 @@ render.make_shader = function(shader)
|
||||||
var shaderobj = json.decode(io.slurp(writejson));
|
var shaderobj = json.decode(io.slurp(writejson));
|
||||||
var obj = shaderobj[os.sys()];
|
var obj = shaderobj[os.sys()];
|
||||||
obj.pipe = render.pipeline(obj);
|
obj.pipe = render.pipeline(obj);
|
||||||
|
shader_cache[shader] = obj;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,6 +309,7 @@ render.make_shader = function(shader)
|
||||||
var obj = compiled[os.sys()];
|
var obj = compiled[os.sys()];
|
||||||
obj.pipe = render.pipeline(obj);
|
obj.pipe = render.pipeline(obj);
|
||||||
|
|
||||||
|
shader_cache[shader] = obj;
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,11 +646,14 @@ render.slice9 = function(tex, pos, bb, scale = [tex.width,tex.height], color = C
|
||||||
|
|
||||||
render.emitter = function(emit)
|
render.emitter = function(emit)
|
||||||
{
|
{
|
||||||
var amt = emit.draw();
|
var amt = Object.values(emit.particles).length;
|
||||||
if (amt === 0) return;
|
if (amt === 0) return;
|
||||||
render.use_shader(parshader);
|
render.use_shader(parshader);
|
||||||
render.use_mat(emit);
|
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;
|
var textssbo;
|
||||||
|
|
|
@ -8,9 +8,7 @@ in vec2 a_uv;
|
||||||
uniform vec2 diffuse_size;
|
uniform vec2 diffuse_size;
|
||||||
|
|
||||||
struct particle {
|
struct particle {
|
||||||
vec2 pos;
|
mat4 model;
|
||||||
float angle;
|
|
||||||
float scale;
|
|
||||||
vec4 color;
|
vec4 color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,21 +26,16 @@ void main()
|
||||||
{
|
{
|
||||||
particle p = par[gl_InstanceIndex];
|
particle p = par[gl_InstanceIndex];
|
||||||
pos = a_pos - 0.5;
|
pos = a_pos - 0.5;
|
||||||
vec2 rot = pos;
|
gl_Position = vp * p.model * vec4(pos, 0.0, 1.0);
|
||||||
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);
|
|
||||||
uv = a_pos;
|
uv = a_pos;
|
||||||
|
color0 = p.color;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@fs fs
|
@fs fs
|
||||||
in vec2 uv;
|
in vec2 uv;
|
||||||
in vec4 color0;
|
|
||||||
|
|
||||||
|
in vec4 color0;
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|
||||||
texture2D diffuse;
|
texture2D diffuse;
|
||||||
|
@ -50,7 +43,7 @@ sampler smp;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
color = texture(sampler2D(diffuse,smp), uv);
|
color = texture(sampler2D(diffuse,smp),uv);
|
||||||
color *= color0;
|
color *= color0;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -13,7 +13,6 @@ uniform vec4 shade;
|
||||||
void frag()
|
void frag()
|
||||||
{
|
{
|
||||||
color = texture(sampler2D(diffuse,smp), uv);
|
color = texture(sampler2D(diffuse,smp), uv);
|
||||||
if (color.a < 0.1) discard;
|
|
||||||
color *= shade;
|
color *= shade;
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "spline.h"
|
#include "spline.h"
|
||||||
#include "yugine.h"
|
#include "yugine.h"
|
||||||
#include "particle.h"
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include <sokol/sokol_time.h>
|
#include <sokol/sokol_time.h>
|
||||||
|
@ -96,7 +95,6 @@ void cpConstraint_free(cpConstraint *c)
|
||||||
void jsfreestr(const char *s) { JS_FreeCString(js, s); }
|
void jsfreestr(const char *s) { JS_FreeCString(js, s); }
|
||||||
QJSCLASS(gameobject)
|
QJSCLASS(gameobject)
|
||||||
QJSCLASS(transform)
|
QJSCLASS(transform)
|
||||||
QJSCLASS(emitter)
|
|
||||||
QJSCLASS(dsp_node)
|
QJSCLASS(dsp_node)
|
||||||
QJSCLASS(texture)
|
QJSCLASS(texture)
|
||||||
QJSCLASS(font)
|
QJSCLASS(font)
|
||||||
|
@ -661,34 +659,6 @@ sg_bindings js2bind(JSValue v)
|
||||||
return bind;
|
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,
|
JSC_CCALL(render_flushtext,
|
||||||
sg_buffer *buf = js2sg_buffer(argv[0]);
|
sg_buffer *buf = js2sg_buffer(argv[0]);
|
||||||
int amt = text_flush(buf);
|
int amt = text_flush(buf);
|
||||||
|
@ -968,24 +938,67 @@ JSC_CCALL(render_setbind,
|
||||||
sg_apply_bindings(&bind);
|
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,
|
JSC_CCALL(render_make_t_ssbo,
|
||||||
JSValue array = argv[0];
|
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)];
|
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++)
|
for (int i = 0; i < js_arrlen(array); i++)
|
||||||
ms[i] = transform2mat(*js2transform(js_getpropidx(array, i)));
|
ms[i] = transform2mat(*js2transform(js_getpropidx(array, i)));
|
||||||
|
|
||||||
sg_buffer *rr = malloc(sizeof(sg_buffer));
|
sg_append_buffer(*b, (&(sg_range){
|
||||||
*rr = sg_make_buffer(&(sg_buffer_desc){
|
.ptr = ms,
|
||||||
.data = {
|
.size = size
|
||||||
.ptr = ms,
|
}));
|
||||||
.size = sizeof(HMM_Mat4)*js_arrlen(array),
|
|
||||||
},
|
|
||||||
.type = SG_BUFFERTYPE_STORAGEBUFFER,
|
|
||||||
.usage = SG_USAGE_IMMUTABLE,
|
|
||||||
.label = "transform buffer"
|
|
||||||
});
|
|
||||||
|
|
||||||
return sg_buffer2js(rr);
|
|
||||||
)
|
)
|
||||||
|
|
||||||
JSC_CCALL(render_spdraw,
|
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, gfx_gui, 0),
|
||||||
MIST_FUNC_DEF(render, imgui_end, 0),
|
MIST_FUNC_DEF(render, imgui_end, 0),
|
||||||
MIST_FUNC_DEF(render, imgui_init, 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))
|
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),
|
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, pos, vec3)
|
||||||
JSC_GETSET(transform, scale, vec3)
|
JSC_GETSET(transform, scale, vec3)
|
||||||
JSC_GETSET(transform, rotation, quat)
|
JSC_GETSET(transform, rotation, quat)
|
||||||
|
@ -1543,10 +1531,21 @@ JSC_CCALL(transform_direction,
|
||||||
return vec32js(HMM_QVRot(js2vec3(argv[0]), t->rotation));
|
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[] = {
|
static const JSCFunctionListEntry js_transform_funcs[] = {
|
||||||
CGETSET_ADD(transform, pos),
|
CGETSET_ADD(transform, pos),
|
||||||
CGETSET_ADD(transform, scale),
|
CGETSET_ADD(transform, scale),
|
||||||
CGETSET_ADD(transform, rotation),
|
CGETSET_ADD(transform, rotation),
|
||||||
|
MIST_FUNC_DEF(transform, phys2d, 3),
|
||||||
MIST_FUNC_DEF(transform, move, 1),
|
MIST_FUNC_DEF(transform, move, 1),
|
||||||
MIST_FUNC_DEF(transform, rotate, 2),
|
MIST_FUNC_DEF(transform, rotate, 2),
|
||||||
MIST_FUNC_DEF(transform, angle, 1),
|
MIST_FUNC_DEF(transform, angle, 1),
|
||||||
|
@ -2399,18 +2398,6 @@ JSC_SCALL(os_make_model,
|
||||||
return v;
|
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,
|
JSC_CCALL(os_make_buffer,
|
||||||
int type = js2number(argv[1]);
|
int type = js2number(argv[1]);
|
||||||
float *b = malloc(sizeof(float)*js_arrlen(argv[0]));
|
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_font, 2),
|
||||||
MIST_FUNC_DEF(os, make_model, 1),
|
MIST_FUNC_DEF(os, make_model, 1),
|
||||||
MIST_FUNC_DEF(os, make_transform, 0),
|
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_buffer, 1),
|
||||||
MIST_FUNC_DEF(os, make_line_prim, 4),
|
MIST_FUNC_DEF(os, make_line_prim, 4),
|
||||||
MIST_FUNC_DEF(os, make_cylinder, 2),
|
MIST_FUNC_DEF(os, make_cylinder, 2),
|
||||||
|
@ -2623,7 +2609,6 @@ void ffi_load() {
|
||||||
QJSCLASSPREP_FUNCS(gameobject);
|
QJSCLASSPREP_FUNCS(gameobject);
|
||||||
QJSCLASSPREP_FUNCS(transform);
|
QJSCLASSPREP_FUNCS(transform);
|
||||||
QJSCLASSPREP_FUNCS(dsp_node);
|
QJSCLASSPREP_FUNCS(dsp_node);
|
||||||
QJSCLASSPREP_FUNCS(emitter);
|
|
||||||
QJSCLASSPREP_FUNCS(warp_gravity);
|
QJSCLASSPREP_FUNCS(warp_gravity);
|
||||||
QJSCLASSPREP_FUNCS(warp_damp);
|
QJSCLASSPREP_FUNCS(warp_damp);
|
||||||
QJSCLASSPREP_FUNCS(texture);
|
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 "font.h"
|
||||||
#include "gameobject.h"
|
#include "gameobject.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "particle.h"
|
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "spline.h"
|
#include "spline.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "particle.h"
|
|
||||||
#include "simplex.h"
|
#include "simplex.h"
|
||||||
#include <wctype.h>
|
#include <wctype.h>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue