particles, sprite animation
This commit is contained in:
parent
5bdf311da9
commit
6aa44042d7
|
@ -79,19 +79,61 @@ component.sprite = Object.copy(component, {
|
||||||
_enghook: make_sprite,
|
_enghook: make_sprite,
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.hide(component.sprite, 'rect');
|
|
||||||
|
|
||||||
component.sprite.impl = {
|
component.sprite.impl = {
|
||||||
|
toJSON() {
|
||||||
|
var j = {};
|
||||||
|
Object.keys(this).forEach(k => j[k] = this[k]);
|
||||||
|
delete j.rect;
|
||||||
|
return j;
|
||||||
|
},
|
||||||
|
|
||||||
set path(x) {
|
set path(x) {
|
||||||
//cmd(12,this.id,prototypes.resani(this.gameobject.__proto__.toString(), x),this.rect);
|
if (this.cancel) {
|
||||||
cmd(12,this.id,x,this.rect);
|
this.cancel();
|
||||||
|
this.cancel = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Resources.is_animation(x)) {
|
||||||
|
this.rect = component.sprite.rect;
|
||||||
|
cmd(12,this.id,x,this.rect);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.rect = SpriteAnim.make(x).frames[0].rect;
|
||||||
|
cmd(12,this.id,x,this.rect);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
get path() {
|
get path() {
|
||||||
var s = cmd(116,this.id);
|
var s = cmd(116,this.id);
|
||||||
if (s === "icons/no_tex.gif") return undefined;
|
if (s === "icons/no_tex.gif") return undefined;
|
||||||
return s;
|
return s;
|
||||||
//return prototypes.resavi(this.gameobject.__proto__.toString(), cmd(116,this.id));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
play() {
|
||||||
|
var frame = 0;
|
||||||
|
var anim = SpriteAnim.make(this.path);
|
||||||
|
var advance = function() {
|
||||||
|
frame = (frame+1)%anim.frames.length;
|
||||||
|
this.rect = anim.frames[frame].rect;
|
||||||
|
cmd(12,this.id,this.path,this.rect);
|
||||||
|
this.cancel = this.gameobject.delay(advance.bind(this), anim.frames[frame].time);
|
||||||
|
}
|
||||||
|
advance.call(this);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
if (!this.cancel) return;
|
||||||
|
this.cancel();
|
||||||
|
this.cancel = undefined;
|
||||||
|
},
|
||||||
|
setframe(f) {
|
||||||
|
this.stop();
|
||||||
|
var anim = SpriteAnim.make(this.path);
|
||||||
|
if (!anim) return;
|
||||||
|
this.rect = anim.frames[f].rect;
|
||||||
|
cmd(12,this.id,this.path,this.rect);
|
||||||
|
},
|
||||||
|
|
||||||
toString() { return "sprite"; },
|
toString() { return "sprite"; },
|
||||||
hide() { this.enabled = false; },
|
hide() { this.enabled = false; },
|
||||||
show() { this.enabled = true; },
|
show() { this.enabled = true; },
|
||||||
|
@ -163,12 +205,18 @@ sprite.inputs.kp2 = function() { this.pos = this.dimensions().scale([-0.5,-1]);
|
||||||
sprite.inputs.kp1 = function() { this.pos = this.dimensions().scale([-1,-1]); };
|
sprite.inputs.kp1 = function() { this.pos = this.dimensions().scale([-1,-1]); };
|
||||||
Object.seal(sprite);
|
Object.seal(sprite);
|
||||||
|
|
||||||
|
/* sprite anim returns a data structure for the given file path
|
||||||
|
frames: array of frames
|
||||||
|
rect: frame rectangle
|
||||||
|
time: miliseconds to hold the frame for
|
||||||
|
loop: true if it should be looped
|
||||||
|
*/
|
||||||
var SpriteAnim = {
|
var SpriteAnim = {
|
||||||
make(path) {
|
make(path) {
|
||||||
if (path.ext() === 'gif')
|
if (path.ext() === 'gif')
|
||||||
return SpriteAnim.gif(path);
|
return SpriteAnim.gif(path);
|
||||||
else if (Resources.is_image(path))
|
else
|
||||||
return SpriteAnim.strip(path);
|
return undefined;
|
||||||
},
|
},
|
||||||
gif(path) {
|
gif(path) {
|
||||||
var anim = {};
|
var anim = {};
|
||||||
|
@ -187,11 +235,13 @@ var SpriteAnim = {
|
||||||
frame.time = 0.05;
|
frame.time = 0.05;
|
||||||
anim.frames.push(frame);
|
anim.frames.push(frame);
|
||||||
}
|
}
|
||||||
|
var times = cmd(224,path);
|
||||||
|
for (var i = 0; i < frames; i++)
|
||||||
|
anim.frames[i].time = times[i]/1000;
|
||||||
anim.loop = true;
|
anim.loop = true;
|
||||||
var dim = Resources.texture.dimensions(path);
|
var dim = Resources.texture.dimensions(path);
|
||||||
dim.y /= frames;
|
dim.y /= frames;
|
||||||
anim.dim = dim;
|
anim.dim = dim;
|
||||||
anim.toJSON = function() { return {}; };
|
|
||||||
return anim;
|
return anim;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -268,106 +318,6 @@ SpriteAnim.strip.doc = 'Given a path and number of frames, converts a horizontal
|
||||||
SpriteAnim.aseprite.doc = 'Given an aseprite json metadata, returns an object of animations defined in the aseprite file.';
|
SpriteAnim.aseprite.doc = 'Given an aseprite json metadata, returns an object of animations defined in the aseprite file.';
|
||||||
SpriteAnim.find.doc = 'Given a path, find the relevant animation for the file.';
|
SpriteAnim.find.doc = 'Given a path, find the relevant animation for the file.';
|
||||||
|
|
||||||
/* Container to play sprites and anim2ds */
|
|
||||||
|
|
||||||
component.char2d = Object.create(component.sprite);
|
|
||||||
component.char2dimpl = {
|
|
||||||
boundingbox() {
|
|
||||||
var dim = this.acur.dim.slice();
|
|
||||||
dim = dim.scale(this.gameobject.scale);
|
|
||||||
var realpos = this.pos.slice();
|
|
||||||
realpos.x = realpos.x * dim.x + (dim.x/2);
|
|
||||||
realpos.y = realpos.y * dim.y + (dim.y/2);
|
|
||||||
return cwh2bb(realpos,dim);
|
|
||||||
},
|
|
||||||
|
|
||||||
anims:{},
|
|
||||||
acur:{},
|
|
||||||
frame: 0,
|
|
||||||
|
|
||||||
play_anim(anim) {
|
|
||||||
this.acur = anim;
|
|
||||||
this.frame = 0;
|
|
||||||
this.gameobject.delay(this.advance.bind(this), this.acur.frames[this.frame].time);
|
|
||||||
this.setsprite();
|
|
||||||
},
|
|
||||||
|
|
||||||
play(name) {
|
|
||||||
if (!(name in this)) {
|
|
||||||
Log.info("Can't find an animation named " + name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.acur === this[name]) {
|
|
||||||
this.timer.start();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.acur = this[name];
|
|
||||||
this.frame = 0;
|
|
||||||
this.timer.time = this.acur.frames[this.frame].time;
|
|
||||||
this.timer.start();
|
|
||||||
this.setsprite();
|
|
||||||
},
|
|
||||||
|
|
||||||
setsprite() {
|
|
||||||
this.rect = this.acur.frames[this.frame].rect;
|
|
||||||
this.path = this.path;
|
|
||||||
},
|
|
||||||
|
|
||||||
advance() {
|
|
||||||
this.frame = (this.frame + 1) % this.acur.frames.length;
|
|
||||||
this.setsprite();
|
|
||||||
this.gameobject.delay(this.advance.bind(this), this.acur.frames[this.frame].time);
|
|
||||||
},
|
|
||||||
|
|
||||||
devance() {
|
|
||||||
this.frame = (this.frame - 1);
|
|
||||||
if (this.frame === -1) this.frame = this.acur.frames-1;
|
|
||||||
this.setsprite();
|
|
||||||
},
|
|
||||||
|
|
||||||
setframe(frame) {
|
|
||||||
this.frame = frame;
|
|
||||||
this.setsprite();
|
|
||||||
},
|
|
||||||
|
|
||||||
pause() {
|
|
||||||
this.timer.pause();
|
|
||||||
},
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
this.setframe(0);
|
|
||||||
this.timer.stop();
|
|
||||||
},
|
|
||||||
|
|
||||||
kill() { cmd(9, this.id); },
|
|
||||||
|
|
||||||
add_anim(anim,name) {
|
|
||||||
if (name in this) return;
|
|
||||||
this[name] = function() {
|
|
||||||
this.play_anim(anim);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
component.char2dimpl.doc = {
|
|
||||||
doc: "An animation player for sprites.",
|
|
||||||
frame: "The current frame of animation.",
|
|
||||||
anims: "A list of all animations in this player.",
|
|
||||||
acur: "The currently playing animation object.",
|
|
||||||
advance: "Advance the animation by one frame.",
|
|
||||||
devance: "Go back one frame in the animation.",
|
|
||||||
setframe: "Set a specific frame of animation.",
|
|
||||||
stop: "Stops the animation and returns to the first frame.",
|
|
||||||
pause: "Pauses the animation sequence in place.",
|
|
||||||
play: "Given an animation string, play it. Equivalent to anim.[name].play().",
|
|
||||||
play_anim: "Play a given animation object.",
|
|
||||||
add_anim: "Add an animation object with the given name."
|
|
||||||
};
|
|
||||||
|
|
||||||
Object.hide(component.char2dimpl, "doc");
|
|
||||||
|
|
||||||
/* Returns points specifying this geometry, with ccw */
|
/* Returns points specifying this geometry, with ccw */
|
||||||
var Geometry = {
|
var Geometry = {
|
||||||
box(w, h) {
|
box(w, h) {
|
||||||
|
@ -907,7 +857,8 @@ component.circle2d.impl = Object.mix({
|
||||||
get pos() { return this.offset; },
|
get pos() { return this.offset; },
|
||||||
set pos(x) { this.offset = x; },
|
set pos(x) { this.offset = x; },
|
||||||
|
|
||||||
}, collider2d.impl);;
|
}, collider2d.impl);
|
||||||
|
|
||||||
|
|
||||||
/* ASSETS */
|
/* ASSETS */
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ var timer = {
|
||||||
|
|
||||||
kill() {
|
kill() {
|
||||||
Register.unregister_obj(this);
|
Register.unregister_obj(this);
|
||||||
|
this.fn = undefined;
|
||||||
},
|
},
|
||||||
|
|
||||||
delay(fn, secs) {
|
delay(fn, secs) {
|
||||||
|
|
|
@ -1382,6 +1382,10 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
ret = ptr2js(cpGearJointNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body, js2number(argv[3]), js2number(argv[4])));
|
ret = ptr2js(cpGearJointNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body, js2number(argv[3]), js2number(argv[4])));
|
||||||
cpSpaceAddConstraint(space,js2ptr(ret));
|
cpSpaceAddConstraint(space,js2ptr(ret));
|
||||||
break;
|
break;
|
||||||
|
case 224:
|
||||||
|
str = js2str(argv[1]);
|
||||||
|
ret = ints2js(gif_delays(str));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str)
|
if (str)
|
||||||
|
|
|
@ -1,36 +1,184 @@
|
||||||
#include "particle.h"
|
#include "particle.h"
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
#include "freelist.h"
|
#include "render.h"
|
||||||
|
#include "particle.sglsl.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
struct emitter make_emitter() {
|
static emitter **emitters;
|
||||||
struct emitter e = {0};
|
|
||||||
arrsetcap(e.particles, 200);
|
static sg_shader par_shader;
|
||||||
|
static sg_pipeline par_pipe;
|
||||||
|
static sg_bindings par_bind;
|
||||||
|
static int draw_count;
|
||||||
|
|
||||||
|
struct par_vert {
|
||||||
|
HMM_Vec2 pos;
|
||||||
|
float angle;
|
||||||
|
float scale;
|
||||||
|
struct rgba color;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct par_vert par_vert;
|
||||||
|
|
||||||
|
void particle_init()
|
||||||
|
{
|
||||||
|
par_shader = sg_make_shader(particle_shader_desc(sg_query_backend()));
|
||||||
|
|
||||||
|
par_pipe = sg_make_pipeline(&(sg_pipeline_desc){
|
||||||
|
.shader = par_shader,
|
||||||
|
.layout = {
|
||||||
|
.attrs = {
|
||||||
|
[1].format = SG_VERTEXFORMAT_FLOAT2,
|
||||||
|
[2].format = SG_VERTEXFORMAT_FLOAT,
|
||||||
|
[3].format = SG_VERTEXFORMAT_FLOAT,
|
||||||
|
[4].format = SG_VERTEXFORMAT_UBYTE4N,
|
||||||
|
[0].format = SG_VERTEXFORMAT_FLOAT2,
|
||||||
|
[0].buffer_index = 1
|
||||||
|
},
|
||||||
|
.buffers[0].step_func = SG_VERTEXSTEP_PER_INSTANCE,
|
||||||
|
},
|
||||||
|
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
|
||||||
|
.label = "particle pipeline",
|
||||||
|
.cull_mode = SG_CULLMODE_BACK,
|
||||||
|
.colors[0].blend = blend_trans,
|
||||||
|
.depth = {
|
||||||
|
.write_enabled = true,
|
||||||
|
.compare = SG_COMPAREFUNC_LESS_EQUAL,
|
||||||
|
.pixel_format = SG_PIXELFORMAT_DEPTH
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
par_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
|
.size = sizeof(par_vert)*500,
|
||||||
|
.type = SG_BUFFERTYPE_VERTEXBUFFER,
|
||||||
|
.usage = SG_USAGE_STREAM,
|
||||||
|
.label = "particle buffer"
|
||||||
|
});
|
||||||
|
|
||||||
|
float circleverts[8] = {
|
||||||
|
0,0,
|
||||||
|
0,1,
|
||||||
|
1,0,
|
||||||
|
1,1,
|
||||||
|
};
|
||||||
|
|
||||||
|
par_bind.vertex_buffers[1] = sg_make_buffer(&(sg_buffer_desc){
|
||||||
|
.data = (sg_range){.ptr = circleverts, .size = sizeof(float)*8},
|
||||||
|
.usage = SG_USAGE_IMMUTABLE
|
||||||
|
});
|
||||||
|
|
||||||
|
par_bind.fs.samplers[0] = sg_make_sampler(&(sg_sampler_desc){});
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter *make_emitter() {
|
||||||
|
emitter *e = NULL;
|
||||||
|
e = malloc(sizeof(*e));
|
||||||
|
e->max = 20;
|
||||||
|
arrsetlen(e->particles, e->max);
|
||||||
|
for (int i = 0; i < arrlen(e->particles); i++)
|
||||||
|
e->particles[i].life = 0;
|
||||||
|
|
||||||
|
e->life = 10;
|
||||||
|
e->explosiveness = 0;
|
||||||
|
e->tte = e->life/e->max;
|
||||||
|
e->color = color_white;
|
||||||
|
e->scale = 20;
|
||||||
|
arrpush(emitters,e);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_emitter(struct emitter e) {
|
void free_emitter(emitter *e)
|
||||||
arrfree(e.particles);
|
{
|
||||||
|
arrfree(e->particles);
|
||||||
|
for (int i = arrlen(emitters)-1; i >= 0; i--)
|
||||||
|
if (emitters[i] == e) {
|
||||||
|
arrdelswap(emitters,i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_emitter(struct emitter e) {
|
void start_emitter(emitter *e)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pause_emitter(struct emitter e) {
|
void pause_emitter(emitter *e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop_emitter(struct emitter e) {
|
void stop_emitter(emitter *e) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitter_step(struct emitter e, double dt) {
|
int emitter_spawn(emitter *e)
|
||||||
for (int i = 0; i < arrlen(e.particles); i++) {
|
{
|
||||||
e.particles[i].pos = HMM_AddV3(e.particles[i].pos, HMM_MulV3F(e.particles[i].v, dt));
|
for (int i = 0; i < e->max; i++) {
|
||||||
e.particles[i].angle = HMM_MulQ(e.particles[i].angle, HMM_MulQF(e.particles[i].angle, dt));
|
if (e->particles[i].life > 0) continue;
|
||||||
e.particles[i].life -= dt;
|
e->particles[i].life = e->life;
|
||||||
|
e->particles[i].pos = (HMM_Vec3){0,0,0};
|
||||||
|
e->particles[i].v = (HMM_Vec3){20,1,0};
|
||||||
|
e->particles[i].angle = 0;
|
||||||
|
e->particles[i].av = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (e.particles[i].life <= 0)
|
void emitter_emit(emitter *e, int count)
|
||||||
arrdelswap(e.particles, i);
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
if (!emitter_spawn(e)) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitters_step(double dt)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < arrlen(emitters); i++)
|
||||||
|
emitter_step(emitters[i], dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitters_draw()
|
||||||
|
{
|
||||||
|
|
||||||
|
draw_count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < arrlen(emitters); i++) {
|
||||||
|
emitter *e = emitters[i];
|
||||||
|
par_bind.fs.images[0] = e->texture->id;
|
||||||
|
for (int j = 0; j < arrlen(e->particles); j++) {
|
||||||
|
particle *p = &e->particles[j];
|
||||||
|
if (p->life <= 0) continue;
|
||||||
|
struct par_vert pv;
|
||||||
|
pv.pos = p->pos.xy;
|
||||||
|
pv.angle = p->angle;
|
||||||
|
pv.scale = p->scale;
|
||||||
|
pv.color = p->color;
|
||||||
|
sg_append_buffer(par_bind.vertex_buffers[0], &(sg_range){.ptr=&pv, .size=sizeof(struct par_vert)});
|
||||||
|
draw_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (draw_count == 0) return;
|
||||||
|
sg_apply_pipeline(par_pipe);
|
||||||
|
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(projection));
|
||||||
|
sg_apply_bindings(&par_bind);
|
||||||
|
sg_draw(0, 4, draw_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void emitter_step(emitter *e, double dt) {
|
||||||
|
for (int i = 0; i < arrlen(e->particles); i++) {
|
||||||
|
if (e->particles[i].life <= 0) continue;
|
||||||
|
e->particles[i].pos = HMM_AddV3(e->particles[i].pos, HMM_MulV3F(e->particles[i].v, dt));
|
||||||
|
e->particles[i].angle += e->particles[i].av*dt;
|
||||||
|
e->particles[i].life -= dt;
|
||||||
|
e->particles[i].color = e->color;
|
||||||
|
e->particles[i].scale = e->scale;
|
||||||
|
|
||||||
|
if (e->particles[i].life <= 0)
|
||||||
|
e->particles[i].life = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
e->tte-=dt;
|
||||||
|
if (e->tte <= 0) {
|
||||||
|
emitter_emit(e,1);
|
||||||
|
e->tte = e->life/e->max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,34 +3,42 @@
|
||||||
|
|
||||||
#include "HandmadeMath.h"
|
#include "HandmadeMath.h"
|
||||||
#include "transform.h"
|
#include "transform.h"
|
||||||
|
#include "texture.h"
|
||||||
|
|
||||||
struct particle {
|
typedef struct particle {
|
||||||
HMM_Vec3 pos;
|
HMM_Vec3 pos;
|
||||||
HMM_Vec3 v; /* velocity */
|
HMM_Vec3 v; /* velocity */
|
||||||
HMM_Quat angle;
|
float angle;
|
||||||
HMM_Quat av; /* angular velocity */
|
float av; /* angular velocity */
|
||||||
|
float scale;
|
||||||
union {
|
double life;
|
||||||
double life;
|
rgba color;
|
||||||
unsigned int next;
|
} particle;
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct emitter {
|
typedef struct emitter {
|
||||||
struct particle *particles;
|
struct particle *particles;
|
||||||
transform3d t;
|
transform3d t;
|
||||||
int max;
|
float explosiveness; /* 0 for a stream, 1 for all at once. Range of values allowed. */
|
||||||
double life;
|
int max; /* number of particles */
|
||||||
void (*seeder)(struct particle *p); /* Called to initialize each particle */
|
double life; /* how long a particle lasts */
|
||||||
|
double tte; /* time to emit */
|
||||||
|
rgba color;
|
||||||
|
float scale;
|
||||||
|
texture *texture;
|
||||||
} emitter;
|
} emitter;
|
||||||
|
|
||||||
struct emitter make_emitter();
|
void particle_init();
|
||||||
void free_emitter(struct emitter e);
|
|
||||||
|
|
||||||
void start_emitter(struct emitter e);
|
emitter *make_emitter();
|
||||||
void pause_emitter(struct emitter e);
|
void free_emitter(emitter *e);
|
||||||
void stop_emitter(struct emitter e);
|
|
||||||
|
|
||||||
void emitter_step(struct emitter e, double dt);
|
void start_emitter(emitter *e);
|
||||||
|
void pause_emitter(emitter *e);
|
||||||
|
void stop_emitter(emitter *e);
|
||||||
|
|
||||||
|
void emitter_emit(emitter *e, int count);
|
||||||
|
void emitters_step(double dt);
|
||||||
|
void emitters_draw();
|
||||||
|
void emitter_step(emitter *e, double dt);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "gameobject.h"
|
#include "gameobject.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "sprite.h"
|
#include "sprite.h"
|
||||||
|
#include "particle.h"
|
||||||
#include "window.h"
|
#include "window.h"
|
||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "stb_ds.h"
|
#include "stb_ds.h"
|
||||||
|
@ -512,6 +513,8 @@ void full_2d_pass(struct window *window)
|
||||||
model_draw_all();
|
model_draw_all();
|
||||||
call_draw();
|
call_draw();
|
||||||
|
|
||||||
|
emitters_draw();
|
||||||
|
|
||||||
//// DEBUG
|
//// DEBUG
|
||||||
if (debugDrawPhysics) {
|
if (debugDrawPhysics) {
|
||||||
gameobject_draw_debugs();
|
gameobject_draw_debugs();
|
||||||
|
|
|
@ -91,6 +91,8 @@ struct rgba {
|
||||||
unsigned char a;
|
unsigned char a;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct rgba rgba;
|
||||||
|
|
||||||
struct boundingbox {
|
struct boundingbox {
|
||||||
float t;
|
float t;
|
||||||
float b;
|
float b;
|
||||||
|
|
|
@ -277,7 +277,6 @@ void slice9_draw(const char *img, HMM_Vec2 pos, HMM_Vec2 dimensions, struct rgba
|
||||||
|
|
||||||
sg_draw(sprite_count * 4, 4, 1);
|
sg_draw(sprite_count * 4, 4, 1);
|
||||||
sprite_count++;
|
sprite_count++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sprite_setframe(struct sprite *sprite, struct glrect *frame) {
|
void sprite_setframe(struct sprite *sprite, struct glrect *frame) {
|
||||||
|
|
|
@ -76,6 +76,12 @@ int gif_nframes(const char *path)
|
||||||
return t->frames;
|
return t->frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int *gif_delays(const char *path)
|
||||||
|
{
|
||||||
|
struct Texture *t = texture_pullfromfile(path);
|
||||||
|
return t->delays;
|
||||||
|
}
|
||||||
|
|
||||||
/* If an empty string or null is put for path, loads default texture */
|
/* If an empty string or null is put for path, loads default texture */
|
||||||
struct Texture *texture_pullfromfile(const char *path) {
|
struct Texture *texture_pullfromfile(const char *path) {
|
||||||
if (!path) return texture_notex();
|
if (!path) return texture_notex();
|
||||||
|
@ -110,7 +116,13 @@ struct Texture *texture_pullfromfile(const char *path) {
|
||||||
tex->height = qoi.height;
|
tex->height = qoi.height;
|
||||||
n = qoi.channels;
|
n = qoi.channels;
|
||||||
} else if (!strcmp(ext, ".gif")) {
|
} else if (!strcmp(ext, ".gif")) {
|
||||||
data = stbi_load_gif_from_memory(raw, rawlen, NULL, &tex->width, &tex->height, &tex->frames, &n, 4);
|
data = stbi_load_gif_from_memory(raw, rawlen, &tex->delays, &tex->width, &tex->height, &tex->frames, &n, 4);
|
||||||
|
int *dd = tex->delays;
|
||||||
|
tex->delays = NULL;
|
||||||
|
arrsetlen(tex->delays, tex->frames);
|
||||||
|
for (int i = 0; i < tex->frames;i++)
|
||||||
|
tex->delays[i] = dd[i];
|
||||||
|
free(dd);
|
||||||
tex->height *= tex->frames;
|
tex->height *= tex->frames;
|
||||||
} else if (!strcmp(ext, ".svg")) {
|
} else if (!strcmp(ext, ".svg")) {
|
||||||
#ifndef NSVG
|
#ifndef NSVG
|
||||||
|
|
|
@ -31,8 +31,11 @@ struct Texture {
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
struct TextureOptions opts;
|
struct TextureOptions opts;
|
||||||
int frames;
|
int frames;
|
||||||
|
int *delays;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct Texture texture;
|
||||||
|
|
||||||
struct Image {
|
struct Image {
|
||||||
struct Texture *tex;
|
struct Texture *tex;
|
||||||
struct glrect frame;
|
struct glrect frame;
|
||||||
|
@ -47,6 +50,7 @@ void texture_sync(const char *path);
|
||||||
char * tex_get_path(struct Texture *tex); // Get image path for texture
|
char * tex_get_path(struct Texture *tex); // Get image path for texture
|
||||||
|
|
||||||
int gif_nframes(const char *path);
|
int gif_nframes(const char *path);
|
||||||
|
int *gif_delays(const char *path);
|
||||||
|
|
||||||
struct glrect tex_get_rect(struct Texture *tex);
|
struct glrect tex_get_rect(struct Texture *tex);
|
||||||
HMM_Vec2 tex_get_dimensions(struct Texture *tex);
|
HMM_Vec2 tex_get_dimensions(struct Texture *tex);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "spline.h"
|
#include "spline.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include "particle.h"
|
||||||
|
|
||||||
#include "datastream.h"
|
#include "datastream.h"
|
||||||
|
|
||||||
|
@ -101,6 +102,11 @@ void c_init() {
|
||||||
window_set_icon("icons/moon.gif");
|
window_set_icon("icons/moon.gif");
|
||||||
window_resize(sapp_width(), sapp_height());
|
window_resize(sapp_width(), sapp_height());
|
||||||
script_evalf("Game.init();");
|
script_evalf("Game.init();");
|
||||||
|
|
||||||
|
particle_init();
|
||||||
|
// emitter *e = make_emitter();
|
||||||
|
// e->texture = texture_pullfromfile("bolt.gif");
|
||||||
|
// start_emitter(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
int frame_fps() { return 1.0/sapp_frame_duration(); }
|
int frame_fps() { return 1.0/sapp_frame_duration(); }
|
||||||
|
@ -114,10 +120,7 @@ static void process_frame()
|
||||||
/* Timers all update every frame - once per monitor refresh */
|
/* Timers all update every frame - once per monitor refresh */
|
||||||
timer_update(elapsed, timescale);
|
timer_update(elapsed, timescale);
|
||||||
|
|
||||||
/* Update at a high level::
|
emitters_step(elapsed);
|
||||||
* Update scene graph
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (sim_play == SIM_PLAY || sim_play == SIM_STEP) {
|
if (sim_play == SIM_PLAY || sim_play == SIM_STEP) {
|
||||||
if (stm_sec(stm_diff(frame_t, updatelast)) > updateMS) {
|
if (stm_sec(stm_diff(frame_t, updatelast)) > updateMS) {
|
||||||
|
|
19
source/shaders/bezier.sglsl
Normal file
19
source/shaders/bezier.sglsl
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
@vs vs
|
||||||
|
in vec2 pos;
|
||||||
|
|
||||||
|
uniform vs_p { mat4 proj; };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = proj * vec4(pos,0.0,1.0);
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@fs fs
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@program particle vs fs
|
45
source/shaders/particle.sglsl
Normal file
45
source/shaders/particle.sglsl
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
@vs vs
|
||||||
|
in vec2 vertex;
|
||||||
|
in vec2 apos;
|
||||||
|
in float angle;
|
||||||
|
in float scale;
|
||||||
|
in vec4 vc;
|
||||||
|
|
||||||
|
out vec4 fcolor;
|
||||||
|
out vec2 uv;
|
||||||
|
|
||||||
|
uniform vs_p { mat4 proj; };
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fcolor = vc;
|
||||||
|
uv = vertex;
|
||||||
|
vec2 v = vertex - 0.5;
|
||||||
|
vec2 p = vec2(
|
||||||
|
cos(angle)*v.x-sin(angle)*v.y,
|
||||||
|
sin(angle)*v.x+cos(angle)*v.y
|
||||||
|
);
|
||||||
|
p += 0.5;
|
||||||
|
p *= scale;
|
||||||
|
p += apos;
|
||||||
|
|
||||||
|
gl_Position = proj * vec4(p, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@fs fs
|
||||||
|
in vec4 fcolor;
|
||||||
|
out vec4 color;
|
||||||
|
|
||||||
|
in vec2 uv;
|
||||||
|
uniform texture2D image;
|
||||||
|
uniform sampler smp;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
color = texture(sampler2D(image,smp),uv);
|
||||||
|
color *= fcolor;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@program particle vs fs
|
Loading…
Reference in a new issue