Move primitive support to javascript

This commit is contained in:
John Alanbrook 2024-05-06 21:59:22 -05:00
parent 97e258ae7c
commit 44b3bf3a7d
22 changed files with 410 additions and 645 deletions

View file

@ -101,7 +101,7 @@ else ifeq ($(OS), IOS)
LDFLAGS += -isysroot $(SDK_PATH) -miphoneos-version-min=13.0
LDFLAGS += -framework Foundation -framework UIKit -framework AudioToolbox -framework Metal -framework MetalKit -framework AVFoundation
CXXFLAGS += -std=c++11
CFLAGS += -x objective-c
CFLAGS += -x objective-c -DIOS
INFO :=$(INFO)_ios
else ifeq ($(OS), wasm) # Then WEB
OS := Web

View file

@ -1605,10 +1605,10 @@ yaml.tojson = function(yaml)
yaml = yaml.replace(/\s/g, '');
yaml = yaml.replace(/,}/g, '}');
yaml = yaml.replace(/,]/g, ']');
yaml = yaml.replace(/,"[^"]+"\:,/, ',');
return yaml;
}
return {
convert,
time,

View file

@ -309,7 +309,6 @@ function process()
frame_t = profile.secs(profile.now());
prosperon.appupdate(dt);
prosperon.emitters_step(dt);
input.procdown();
if (sim.mode === "play" || sim.mode === "step") {
@ -342,7 +341,6 @@ function process()
render.sprite_flush();
});
render.sprite_flush();*/
render.emitters(); // blits emitters
prosperon.draw(); // draw calls
debug.draw(); // calls needed debugs
render.flush();

View file

@ -19,6 +19,8 @@
#include <string.h>
#include "yugine.h"
#include "jsffi.h"
#include "texture.h"
#include "sokol/sokol_gfx.h"
@ -40,14 +42,6 @@ cgltf_attribute *get_attr_type(cgltf_primitive *p, cgltf_attribute_type t)
return NULL;
}
unsigned short pack_short_texcoord(float x, float y)
{
unsigned short s;
char xc = x*255;
char yc = y*255;
return (((unsigned short)yc) << 8) | xc;
}
unsigned short pack_short_tex(float c) { return c * USHRT_MAX; }
uint32_t pack_int10_n2(float *norm)
@ -81,12 +75,16 @@ void mesh_add_material(primitive *prim, cgltf_material *mat)
pmat->diffuse = texture_from_file("icons/moon.gif");
}
sg_buffer texcoord_floats(float *f, int verts, int comp)
sg_buffer texcoord_floats(float *f, int n)
{
int n = verts*comp;
unsigned short packed[n];
for (int i = 0; i < n; i++)
packed[i] = pack_short_tex(f[i]);
for (int i = 0; i < n; i++) {
float v = f[i];
if (v < 0) v = 0;
if (v > 1) v = 1;
packed[i] = pack_short_tex(v);
printf("val: %g, packed: %u\n", v, packed[i]);
}
return sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(packed),
@ -94,10 +92,43 @@ sg_buffer texcoord_floats(float *f, int verts, int comp)
});
}
sg_buffer normal_floats(float *f, int verts, int comp)
sg_buffer par_idx_buffer(uint32_t *p, int v)
{
uint32_t packed_norms[verts];
for (int v = 0, i = 0; v < verts; v++, i+= comp)
uint16_t idx[v];
for (int i = 0; i < v; i++) idx[i] = p[i];
return sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(idx),
.type = SG_BUFFERTYPE_INDEXBUFFER
});
}
sg_buffer float_buffer(float *f, int v)
{
return sg_make_buffer(&(sg_buffer_desc){
.data = (sg_range){
.ptr = f,
.size = sizeof(*f)*v
}
});
}
sg_buffer index_buffer(float *f, int verts)
{
uint16_t idxs[verts];
for (int i = 0; i < verts; i++)
idxs[i] = f[i];
return sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(idxs),
.type = SG_BUFFERTYPE_INDEXBUFFER,
});
}
sg_buffer normal_floats(float *f, int n)
{
uint32_t packed_norms[n/3];
for (int v = 0, i = 0; v < n/3; v++, i+= 3)
packed_norms[v] = pack_int10_n2(f+i);
return sg_make_buffer(&(sg_buffer_desc){
@ -106,37 +137,37 @@ sg_buffer normal_floats(float *f, int verts, int comp)
});
}
sg_buffer ubyten_buffer(float *f, int v, int c)
sg_buffer ubyten_buffer(float *f, int v)
{
unsigned char b[v*c];
for (int i = 0; i < (v*c); i++)
unsigned char b[v];
for (int i = 0; i < (v); i++)
b[i] = f[i]*255;
return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)});
}
sg_buffer ubyte_buffer(float *f, int v, int c)
sg_buffer ubyte_buffer(float *f, int v)
{
unsigned char b[v*c];
for (int i = 0; i < (v*c); i++)
unsigned char b[v];
for (int i = 0; i < (v); i++)
b[i] = f[i];
return sg_make_buffer(&(sg_buffer_desc){.data=SG_RANGE(b)});
}
sg_buffer joint_buf(float *f, int v, int c)
sg_buffer joint_buf(float *f, int v)
{
char joints[v*c];
for (int i = 0; i < (v*c); i++)
char joints[v];
for (int i = 0; i < (v); i++)
joints[i] = f[i];
return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(joints)});
}
sg_buffer weight_buf(float *f, int v, int c)
sg_buffer weight_buf(float *f, int v)
{
unsigned char weights[v*c];
for (int i = 0; i < (v*c); i++)
unsigned char weights[v];
for (int i = 0; i < (v); i++)
weights[i] = f[i]*255;
return sg_make_buffer(&(sg_buffer_desc){ .data = SG_RANGE(weights)});
@ -147,6 +178,22 @@ HMM_Vec3 index_to_vert(uint32_t idx, float *f)
return (HMM_Vec3){f[idx*3], f[idx*3+1], f[idx*3+2]};
}
void primitive_gen_indices(primitive *prim)
{
if (prim->idx_count == 0) return;
uint16_t *idxs = malloc(sizeof(*idxs)*prim->idx_count);
for (int z = 0; z < prim->idx_count; z++)
idxs[z] = z;
prim->idx = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs,
.data.size = sizeof(uint16_t) * prim->idx_count,
.type = SG_BUFFERTYPE_INDEXBUFFER});
free(idxs);
}
struct primitive mesh_add_primitive(cgltf_primitive *prim)
{
primitive retp = (primitive){0};
@ -168,24 +215,12 @@ struct primitive mesh_add_primitive(cgltf_primitive *prim)
});
retp.idx_count = n;
free(idxs);
} else {
YughWarn("Model does not have indices. Generating them.");
int c = cgltf_accessor_unpack_floats(prim->attributes[0].data, NULL, 0);
retp.idx_count = c;
idxs = malloc(sizeof(*idxs)*c);
for (int z = 0; z < c; z++)
idxs[z] = z;
retp.idx = sg_make_buffer(&(sg_buffer_desc){
.data.ptr = idxs,
.data.size = sizeof(uint16_t) * c,
.type = SG_BUFFERTYPE_INDEXBUFFER});
retp.idx_count = cgltf_accessor_unpack_floats(prim->attributes[0].data, NULL, 0);
primitive_gen_indices(&retp);
}
free(idxs);
printf("adding material\n");
mesh_add_material(&retp, prim->material);
@ -208,26 +243,26 @@ struct primitive mesh_add_primitive(cgltf_primitive *prim)
break;
case cgltf_attribute_type_normal:
retp.norm = normal_floats(vs, verts, comp);
retp.norm = normal_floats(vs, n);
break;
case cgltf_attribute_type_tangent:
break;
case cgltf_attribute_type_color:
retp.color = ubyten_buffer(vs,verts,comp);
retp.color = ubyten_buffer(vs,n);
break;
case cgltf_attribute_type_weights:
retp.weight = ubyten_buffer(vs, verts, comp);
retp.weight = ubyten_buffer(vs, n);
break;
case cgltf_attribute_type_joints:
retp.bone = ubyte_buffer(vs, verts, comp);
retp.bone = ubyte_buffer(vs, n);
break;
case cgltf_attribute_type_texcoord:
retp.uv = texcoord_floats(vs, verts, comp);
retp.uv = texcoord_floats(vs, n);
break;
case cgltf_attribute_type_invalid:
YughWarn("Invalid type.");
@ -505,6 +540,68 @@ void model_draw_go(model *model, gameobject *go, gameobject *cam)
}
}
int mat2type(int mat)
{
switch(mat) {
case MAT_POS:
case MAT_WH:
case MAT_ST:
return SG_VERTEXFORMAT_FLOAT2;
case MAT_UV:
case MAT_TAN:
return SG_VERTEXFORMAT_USHORT2N;
case MAT_NORM:
return SG_VERTEXFORMAT_UINT10_N2;
case MAT_BONE:
return SG_VERTEXFORMAT_UBYTE4;
case MAT_WEIGHT:
case MAT_COLOR:
return SG_VERTEXFORMAT_UBYTE4N;
case MAT_ANGLE:
return SG_VERTEXFORMAT_FLOAT;
};
return 0;
}
sg_buffer mat2buffer(int mat, primitive *p)
{
switch(mat) {
case MAT_POS: return p->pos;
case MAT_NORM: return p->norm;
case MAT_UV: return p->uv;
case MAT_BONE: return p->bone;
case MAT_WEIGHT: return p->weight;
case MAT_COLOR: return p->color;
};
return p->pos;
}
sg_bindings primitive_bindings(primitive *p, JSValue v)
{
sg_bindings b = {0};
JSValue inputs = js_getpropstr(js_getpropstr(v, "vs"), "inputs");
for (int i = 0; i < js_arrlen(inputs); i++) {
JSValue attr = js_getpropidx(inputs, i);
int mat = js2number(js_getpropstr(attr, "mat"));
int slot = js2number(js_getpropstr(attr, "slot"));
sg_buffer buf = mat2buffer(mat,p);
if (!buf.id) {
// ERROR
}
b.vertex_buffers[slot] = buf;
}
b.index_buffer = p->idx;
return b;
}
void primitive_free(primitive *prim)
{
}
void material_free(material *mat)
{

View file

@ -15,17 +15,20 @@
#define MAT_WEIGHT 4
#define MAT_COLOR 5
#define MAT_TAN 6
#define MAT_ANGLE 7
#define MAT_WH 8
#define MAT_ST 9
typedef struct material {
texture *diffuse;
texture *metalrough;
struct texture *diffuse;
struct texture *metalrough;
float metal;
float rough;
texture *normal;
struct texture *normal;
float nrm;
texture *occlusion;
struct texture *occlusion;
float occl;
texture *emissive;
struct texture *emissive;
HMM_Vec3 emis;
} material;
@ -83,6 +86,20 @@ struct model *model_make(const char *path);
void model_free(model *m);
void model_draw_go(model *m, gameobject *go, gameobject *cam);
sg_bindings primitive_bindings(primitive *p, JSValue pipe);
void primitive_gen_indices(primitive *prim);
int mat2type(int mat);
sg_buffer float_buffer(float *f, int v);
sg_buffer index_buffer(float *f, int verts);
sg_buffer texcoord_floats(float *f, int n);
sg_buffer par_idx_buffer(uint32_t *i, int v);
sg_buffer normal_floats(float *f, int n);
sg_buffer ubyten_buffer(float *f, int v);
sg_buffer ubyte_buffer(float *f, int v);
sg_buffer joint_buf(float *f, int v);
sg_buffer weight_buf(float *f, int v);
void primitive_free(primitive *prim);
material *material_make();
void material_free(material *mat);

View file

@ -111,9 +111,6 @@ struct circle_vertex {
float fill;
};
static sg_pipeline g3_pipe;
static sg_shader g3_shader;
void debug_nextpass()
{
point_sc = point_c;
@ -196,14 +193,6 @@ static sg_shader_uniform_block_desc time_ubo = {
void debugdraw_init()
{
/*
g3_shader = sg_make_shader(grid3d_shader_desc(sg_query_backend()));
g3_pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = g3_shader,
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
.index_type = SG_INDEXTYPE_UINT32
});
*/
point_shader = sg_make_shader(point_shader_desc(sg_query_backend()));
point_pipe = sg_make_pipeline(&(sg_pipeline_desc){

View file

@ -33,8 +33,6 @@ struct text_vert {
static struct text_vert *text_buffer;
void font_init() {
bind_text.vertex_buffers[1] = sprite_quad;
bind_text.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct text_vert),
.type = SG_BUFFERTYPE_VERTEXBUFFER,

View file

@ -32,6 +32,7 @@
#include "render.h"
#include "model.h"
#include "HandmadeMath.h"
#include "par/par_streamlines.h"
#if (defined(_WIN32) || defined(__WIN32__))
#include <direct.h>
@ -61,6 +62,11 @@ const char *js2str(JSValue v) {
return JS_ToCString(js, v);
}
void sg_buffer_free(sg_buffer *b)
{
sg_dealloc_buffer(*b);
}
void jsfreestr(const char *s) { JS_FreeCString(js, s); }
QJSCLASS(gameobject)
QJSCLASS(transform3d)
@ -76,6 +82,8 @@ QJSCLASS(material)
QJSCLASS(model)
QJSCLASS(window)
QJSCLASS(constraint)
QJSCLASS(primitive)
QJSCLASS(sg_buffer)
static JSValue sound_proto;
sound *js2sound(JSValue v) { return js2dsp_node(v)->data; }
@ -111,6 +119,11 @@ JSValue js_getpropstr(JSValue v, const char *str)
return p;
}
void js_setpropstr(JSValue v, const char *str, JSValue p)
{
JS_SetPropertyStr(js, v, str, p);
}
static inline cpBody *js2body(JSValue v) { return js2gameobject(v)->body; }
JSValue strarr2js(char **c)
@ -578,6 +591,21 @@ static const JSCFunctionListEntry js_warp_damp_funcs [] = {
CGETSET_ADD(warp_damp, damp)
};
sg_bindings js2bind(JSValue mat, JSValue prim)
{
sg_bindings bind = {0};
for (int i = 0; i < js_arrlen(mat); i++) {
bind.fs.images[i] = js2texture(js_getpropidx(mat, i))->id;
bind.fs.samplers[i] = std_sampler;
}
bind.vertex_buffers[0] = *js2sg_buffer(js_getpropstr(prim, "pos"));
bind.index_buffer = *js2sg_buffer(js_getpropstr(prim, "index"));
bind.vertex_buffers[1] = *js2sg_buffer(js_getpropstr(prim, "uv"));
return bind;
}
JSC_GETSET(emitter, life, number)
JSC_GETSET(emitter, life_var, number)
JSC_GETSET(emitter, speed, number)
@ -595,11 +623,9 @@ JSC_GETSET(emitter, die_after_collision, boolean)
JSC_GETSET(emitter, persist, number)
JSC_GETSET(emitter, persist_var, number)
JSC_GETSET(emitter, warp_mask, bitmask)
JSC_GETSET(emitter, texture, texture)
JSC_CCALL(emitter_start, start_emitter(js2emitter(this)))
JSC_CCALL(emitter_stop, stop_emitter(js2emitter(this)))
JSC_CCALL(emitter_emit, emitter_emit(js2emitter(this), js2number(argv[0])))
JSC_CCALL(emitter_emit, emitter_emit(js2emitter(this), js2number(argv[0]), js2transform2d(argv[1])))
JSC_CCALL(emitter_step, emitter_step(js2emitter(this), js2number(argv[0]), js2transform2d(argv[1])))
JSC_CCALL(emitter_draw, emitter_draw(js2emitter(this), js2bind(argv[0], argv[1])))
JSC_CCALL(render_grid, draw_grid(js2number(argv[0]), js2number(argv[1]), js2color(argv[2]));)
JSC_CCALL(render_point, draw_cppoint(js2vec2(argv[0]), js2number(argv[1]), js2color(argv[2])))
@ -624,7 +650,6 @@ JSC_CCALL(render_line3d,
arrfree(v1);
);
JSC_CCALL(render_emitters, emitters_draw(&useproj))
JSC_CCALL(render_flush, debug_flush(&useproj); )
JSC_CCALL(render_flushtext, text_flush())
@ -740,20 +765,40 @@ JSC_CCALL(render_pipeline3d,
return number2js(pipe.id);
)
JSC_CCALL(render_pipelinetext,
sg_shader fontshader = js2shader(argv[0]);
sg_pipeline_desc p = {0};
p.shader = fontshader;
sg_vertex_layout_state js2layout(JSValue v)
{
sg_vertex_layout_state st = {0};
st.attrs[0].format = SG_VERTEXFORMAT_FLOAT2;
st.attrs[0].buffer_index = 1;
st.attrs[1].format = SG_VERTEXFORMAT_FLOAT2;
st.attrs[2].format = SG_VERTEXFORMAT_FLOAT2;
st.attrs[3].format = SG_VERTEXFORMAT_USHORT2N;
st.attrs[4].format = SG_VERTEXFORMAT_USHORT2N;
st.attrs[5].format = SG_VERTEXFORMAT_UBYTE4N;
st.buffers[0].step_func = SG_VERTEXSTEP_PER_INSTANCE;
p.layout = st;
JSValue inputs = js_getpropstr(js_getpropstr(v, "vs"), "inputs");
for (int i = 0; i < js_arrlen(inputs); i++) {
JSValue attr = js_getpropidx(inputs, i);
int slot = js2number(js_getpropstr(attr, "slot"));
int mat = js2number(js_getpropstr(attr, "mat"));
st.attrs[slot].format = mat2type(mat);
st.attrs[slot].buffer_index = slot;
}
return st;
}
JSC_CCALL(render_pipelineparticle,
sg_pipeline_desc p = {0};
p.shader = js2shader(argv[0]);
p.layout = js2layout(argv[0]);
p.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP;
p.index_type = SG_INDEXTYPE_UINT16;
//p.cull_mode = SG_CULLMODE_BACK;
//p.colors[0].blend = blend_trans;
//p.depth.write_enabled = true;
//p.depth.compare = SG_COMPAREFUNC_LESS_EQUAL;
sg_pipeline pipe = sg_make_pipeline(&p);
return number2js(pipe.id);
)
JSC_CCALL(render_pipelinetext,
sg_pipeline_desc p = {0};
p.shader = js2shader(argv[0]);
p.layout = js2layout(argv[0]);
p.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP;
p.colors[0].blend = blend_trans;
@ -762,18 +807,15 @@ JSC_CCALL(render_pipelinetext,
)
JSC_CCALL(render_pipeline,
sg_shader sgshader = js2shader(argv[0]);
sg_pipeline_desc pdesc = {0};
pdesc.shader = sgshader;
pdesc.cull_mode = SG_CULLMODE_FRONT;
pdesc.layout.attrs[0].format = SG_VERTEXFORMAT_FLOAT2;
pdesc.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP;
sg_pipeline_desc p = {0};
p.shader = js2shader(argv[0]);
p.layout = js2layout(argv[0]);
//p.cull_mode = SG_CULLMODE_FRONT;
p.index_type = SG_INDEXTYPE_UINT16;
if (js2boolean(js_getpropstr(argv[0], "blend")))
pdesc.colors[0].blend = blend_trans;
p.colors[0].blend = blend_trans;
sg_pipeline pipe = sg_make_pipeline(&pdesc);
sg_pipeline pipe = sg_make_pipeline(&p);
return number2js(pipe.id);
)
@ -822,16 +864,10 @@ JSC_CCALL(render_setunim4,
);
JSC_CCALL(render_spdraw,
sg_bindings bind = {0};
bind.vertex_buffers[0] = sprite_quad;
for (int i = 0; i < js_arrlen(argv[0]); i++) {
bind.fs.images[i] = js2texture(js_getpropidx(argv[0], i))->id;
bind.fs.samplers[i] = std_sampler;
}
sg_bindings bind = js2bind(argv[0], argv[1]);
sg_apply_bindings(&bind);
sg_draw(0,4,1);
int p = js2number(js_getpropstr(argv[1], "count"));
sg_draw(0,p,1);
)
JSC_CCALL(render_setpipeline,
@ -847,7 +883,6 @@ static const JSCFunctionListEntry js_render_funcs[] = {
MIST_FUNC_DEF(render, poly, 2),
MIST_FUNC_DEF(render, line, 3),
MIST_FUNC_DEF(render, line3d, 2),
MIST_FUNC_DEF(render, emitters, 0),
MIST_FUNC_DEF(render, flushtext, 0),
MIST_FUNC_DEF(render, flush, 0),
MIST_FUNC_DEF(render, end_pass, 0),
@ -858,9 +893,10 @@ static const JSCFunctionListEntry js_render_funcs[] = {
MIST_FUNC_DEF(render, pipeline, 1),
MIST_FUNC_DEF(render, pipeline3d, 1),
MIST_FUNC_DEF(render, pipelinetext, 1),
MIST_FUNC_DEF(render, pipelineparticle, 1),
MIST_FUNC_DEF(render, setuniv3, 2),
MIST_FUNC_DEF(render, setuniv, 2),
MIST_FUNC_DEF(render, spdraw, 2),
MIST_FUNC_DEF(render, spdraw, 1),
MIST_FUNC_DEF(render, setuniproj, 2),
MIST_FUNC_DEF(render, setunim4, 3),
MIST_FUNC_DEF(render, setuniv2, 2),
@ -958,7 +994,6 @@ static const JSCFunctionListEntry js_input_funcs[] = {
MIST_FUNC_DEF(input, cursor_img, 1)
};
JSC_CCALL(prosperon_emitters_step, emitters_step(js2number(argv[0])))
JSC_CCALL(prosperon_phys2d_step, phys2d_update(js2number(argv[0])))
JSC_CCALL(prosperon_window_render, openglRender(&mainwin, js2transform2d(argv[0]), js2number(argv[1])))
JSC_CCALL(prosperon_guid,
@ -972,7 +1007,6 @@ JSC_CCALL(prosperon_guid,
)
static const JSCFunctionListEntry js_prosperon_funcs[] = {
MIST_FUNC_DEF(prosperon, emitters_step, 1),
MIST_FUNC_DEF(prosperon, phys2d_step, 1),
MIST_FUNC_DEF(prosperon, window_render, 0),
MIST_FUNC_DEF(prosperon, guid, 0),
@ -1247,8 +1281,6 @@ static const JSCFunctionListEntry js_physics_funcs[] = {
MIST_FUNC_DEF(physics, make_gravity, 0),
};
JSC_CCALL(model_draw_go,
model_draw_go(js2model(this), js2gameobject(argv[0]), js2gameobject(argv[1]))
);
@ -1275,10 +1307,9 @@ static const JSCFunctionListEntry js_emitter_funcs[] = {
CGETSET_ADD(emitter, persist),
CGETSET_ADD(emitter, persist_var),
CGETSET_ADD(emitter, warp_mask),
MIST_FUNC_DEF(emitter, start, 0),
MIST_FUNC_DEF(emitter, stop, 0),
MIST_FUNC_DEF(emitter, emit, 1),
CGETSET_ADD(emitter, texture),
MIST_FUNC_DEF(emitter, step, 1),
MIST_FUNC_DEF(emitter, draw, 1)
};
JSC_GETSET(transform2d, pos, vec2)
@ -1685,8 +1716,12 @@ JSValue js_os_sys(JSContext *js, JSValue this, int argc, JSValue *argv)
return str2js("linux");
#elif defined(_WIN32) || defined(_WIN64)
return str2js("windows");
#elif defined(IOS)
return str2js("ios");
#elif defined(__APPLE__)
return str2js("macos");
#elif define(__EMSCRIPTEN__)
return str2js("web");
#endif
return JS_UNDEFINED;
}
@ -1699,7 +1734,6 @@ JSC_SSCALL(os_eval, ret = script_eval(str, str2))
JSC_SCALL(os_capture, capture_screen(js2number(argv[1]), js2number(argv[2]), js2number(argv[4]), js2number(argv[5]), str))
JSC_CCALL(os_sprite,
if (js2boolean(argv[0])) return JS_GetClassProto(js,js_sprite_id);
return sprite2js(sprite_make());
)
@ -1768,9 +1802,89 @@ JSC_CCALL(os_make_transform2d,
JSC_SCALL(os_system, return number2js(system(str)); )
JSC_SCALL(os_make_model, ret = model2js(model_make(str)))
JSC_CCALL(os_make_emitter, ret = emitter2js(make_emitter()))
JSC_CCALL(os_make_buffer,
int type = js2number(argv[1]);
float *b = malloc(sizeof(float)*js_arrlen(argv[0]));
for (int i = 0; i < js_arrlen(argv[0]); i++)
b[i] = js2number(js_getpropidx(argv[0],i));
sg_buffer *p = malloc(sizeof(sg_buffer));
switch(type) {
case 0:
*p = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(float)*js_arrlen(argv[0]),
.data = b
});
break;
case 1:
*p = index_buffer(b, js_arrlen(argv[0]));
break;
case 2:
*p = texcoord_floats(b, js_arrlen(argv[0]));
break;
}
free(b);
return sg_buffer2js(p);
)
JSC_CCALL(os_make_line_prim,
JSValue prim = JS_NewObject(js);
HMM_Vec2 *v = js2cpvec2arr(argv[0]);
parsl_position par_v[arrlen(v)];
for (int i = 0; i < arrlen(v); i++) {
par_v[i].x = v[i].x;
par_v[i].y = v[i].y;
}
parsl_context *par_ctx = parsl_create_context((parsl_config){
.thickness = js2number(argv[1]),
.flags= PARSL_FLAG_ANNOTATIONS,
.u_mode = PAR_U_MODE_NORMALIZED_DISTANCE
});
uint16_t spine_lens[] = {arrlen(v)};
parsl_mesh *m = parsl_mesh_from_lines(par_ctx, (parsl_spine_list){
.num_vertices = arrlen(v),
.num_spines = 1,
.vertices = par_v,
.spine_lengths = spine_lens
});
sg_buffer *pos = malloc(sizeof(*pos));
*pos = sg_make_buffer(&(sg_buffer_desc){
.data = (sg_range){
.ptr = m->positions,
.size = sizeof(parsl_position)*m->num_vertices
}
});
js_setpropstr(prim, "pos", sg_buffer2js(pos));
js_setpropstr(prim, "count", number2js(m->num_triangles*3));
sg_buffer *idx = malloc(sizeof(*idx));
*idx = par_idx_buffer(m->triangle_indices, m->num_triangles*3);
js_setpropstr(prim, "index", sg_buffer2js(idx));
printf("there are %d verts\n", m->num_vertices);
float uv[m->num_vertices*2];
for (int i = 0; i < m->num_vertices; i++) {
uv[i*2] = m->annotations[i].u_along_curve;
uv[i*2+1] = m->annotations[i].v_across_curve;
printf("uv is %g,%g\n", uv[i*2], uv[i*2+1]);
}
sg_buffer *buv = malloc(sizeof(*buv));
*buv = texcoord_floats(uv, m->num_vertices*2);
//*buv = float_buffer(uv, m->num_vertices*2);
js_setpropstr(prim, "uv", sg_buffer2js(buv));
return prim;
)
static const JSCFunctionListEntry js_os_funcs[] = {
MIST_FUNC_DEF(os,sprite,1),
MIST_FUNC_DEF(os,sprite,0),
MIST_FUNC_DEF(os, cwd, 0),
MIST_FUNC_DEF(os, env, 1),
MIST_FUNC_DEF(os, sys, 0),
@ -1789,6 +1903,9 @@ 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_transform2d, 1),
MIST_FUNC_DEF(os, make_emitter, 0),
MIST_FUNC_DEF(os, make_buffer, 1),
MIST_FUNC_DEF(os, make_line_prim, 2),
};
#include "steam.h"

View file

@ -139,5 +139,6 @@ JSValue js_getpropidx(JSValue v, uint32_t i);
JSValue js_getpropstr(JSValue v, const char *str);
const char *js2str(JSValue v);
void jsfreestr(const char *str);
int js_arrlen(JSValue v);
#endif

View file

@ -1,119 +1,37 @@
#include "particle.h"
#include "stb_ds.h"
#include "render.h"
#include "particle.sglsl.h"
#include "2dphysics.h"
#include "log.h"
#include "simplex.h"
#include "pthread.h"
#include "math.h"
#define SCHED_IMPLEMENTATION
#include "sched.h"
static emitter **emitters;
static sg_shader par_shader;
static sg_pipeline par_pipe;
static sg_bindings par_bind;
static int draw_count;
#define MAX_PARTICLES 1000000
struct scheduler sched;
void *mem;
struct par_vert {
HMM_Vec2 pos;
float angle;
HMM_Vec2 scale;
struct rgba color;
};
typedef struct par_vert par_vert;
void particle_init()
{
sched_size needed;
scheduler_init(&sched, &needed, 1, NULL);
mem = calloc(needed, 1);
scheduler_start(&sched,mem);
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_FLOAT2,
[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
}
});
par_bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(par_vert)*MAX_PARTICLES,
.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] = sprite_quad;
par_bind.fs.samplers[0] = std_sampler;
}
#include "log.h"
emitter *make_emitter() {
emitter *e = calloc(sizeof(*e),1);
e->max = 20;
arrsetcap(e->particles, e->max);
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);
//sampler_add(&e->color, 0, (HMM_Vec4){1,1,1,1});
e->scale = 1;
e->speed = 20;
e->texture = NULL;
arrpush(emitters,e);
e->buffer = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(struct par_vert),
.type = SG_BUFFERTYPE_VERTEXBUFFER,
.usage = SG_USAGE_STREAM
});
return e;
}
void emitter_free(emitter *e)
{
YughWarn("kill emitter");
arrfree(e->particles);
for (int i = arrlen(emitters)-1; i >= 0; i--)
if (emitters[i] == e) {
arrdelswap(emitters,i);
break;
}
arrfree(e->verts);
free(e);
}
void start_emitter(emitter *e) { e->on = 1; }
void stop_emitter(emitter *e) { e->on = 0; }
/* Variate a value around variance. Variance between 0 and 1. */
float variate(float val, float variance)
@ -121,98 +39,68 @@ float variate(float val, float variance)
return val + val*(frand(variance)-(variance/2));
}
int emitter_spawn(emitter *e)
int emitter_spawn(emitter *e, transform2d *t)
{
particle p;
p.life = e->life;
p.pos = (HMM_Vec4){e->t.pos.x,e->t.pos.y,0,0};
float newan = e->t.rotation.Elements[0]+(2*HMM_PI*(frand(e->divergence)-(e->divergence/2)));
p.pos = (HMM_Vec4){t->pos.x,t->pos.y,0,0};
float newan = t->angle * HMM_TurnToRad*(frand(e->divergence)-(e->divergence/2));
HMM_Vec2 norm = HMM_V2Rotate((HMM_Vec2){0,1}, newan);
p.v = HMM_MulV4F((HMM_Vec4){norm.x,norm.y,0,0}, variate(e->speed, e->variation));
p.angle = 0;
p.scale = variate(e->scale, e->scale_var);
// p.av = 1;
p.angle = newan;
p.scale = variate(e->scale*t->scale.x, e->scale_var);
arrput(e->particles,p);
return 1;
}
void emitter_emit(emitter *e, int count)
void emitter_emit(emitter *e, int count, transform2d *t)
{
for (int i = 0; i < count; i++)
emitter_spawn(e);
emitter_spawn(e, t);
}
void emitters_step(double dt)
void emitter_draw(emitter *e, sg_bindings bind)
{
for (int i = 0; i < arrlen(emitters); i++)
emitter_step(emitters[i], dt);
}
static struct par_vert pv[MAX_PARTICLES];
void parallel_pv(emitter *e, struct scheduler *sched, struct sched_task_partition t, sched_uint thread_num)
{
for (int i=t.start; i < t.end; i++) {
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];
pv[i].pos = p->pos.xy;
pv[i].angle = p->angle;
float s = p->scale;
if (p->time < e->grow_for)
s = lerp(p->time/e->grow_for, 0, p->scale);
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))
s = lerp((p->time-(p->life-e->shrink_for))/e->shrink_for, p->scale, 0);
pv[i].scale = HMM_ScaleV2((HMM_Vec2){e->texture->width,e->texture->height}, s);
pv[i].color = vec2rgba(p->color);
}
}
void emitter_draw(emitter *e, gameobject *go)
{
sg_apply_pipeline(par_pipe);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(useproj));
sg_apply_bindings(&par_bind);
par_bind.fs.images[0] = e->texture->id;
struct sched_task task;
scheduler_add(&sched, &task, parallel_pv, e, arrlen(e->particles), arrlen(e->particles)/sched.threads_num);
scheduler_join(&sched, &task);
sg_append_buffer(par_bind.vertex_buffers[0], &(sg_range){.ptr=&pv, .size=sizeof(struct par_vert)*arrlen(e->particles)});
draw_count += arrlen(e->particles);
sg_draw(0,4,draw_count);
}
void emitters_draw(HMM_Mat4 *proj)
{
if (arrlen(emitters) == 0) return;
int draw_count = 0;
for (int i = 0; i < arrlen(emitters); i++) {
emitter *e = emitters[i];
par_bind.fs.images[0] = e->texture->id;
struct sched_task task;
scheduler_add(&sched, &task, parallel_pv, e, arrlen(e->particles), arrlen(e->particles)/sched.threads_num);
scheduler_join(&sched, &task);
sg_append_buffer(par_bind.vertex_buffers[0], &(sg_range){.ptr=&pv, .size=sizeof(struct par_vert)*arrlen(e->particles)});
draw_count += arrlen(e->particles);
e->verts[i].scale = lerp((p->time-(p->life-e->shrink_for))/e->shrink_for, p->scale, 0);*/
e->verts[i].color = vec2rgba(p->color);
}
sg_apply_pipeline(par_pipe);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(*proj));
sg_apply_bindings(&par_bind);
sg_draw(0, 4, draw_count);
sg_range verts;
verts.ptr = e->verts;
verts.size = sizeof(*e->verts)*arrlen(e->verts);
if (sg_query_buffer_will_overflow(e->buffer, verts.size))
e->buffer = sg_make_buffer(&(sg_buffer_desc){
.size = verts.size,
.type = SG_BUFFERTYPE_VERTEXBUFFER,
.usage = SG_USAGE_STREAM
});
sg_append_buffer(e->buffer, &verts);
bind.vertex_buffers[0] = e->buffer;
sg_apply_bindings(&bind);
sg_draw(0,4,arrlen(e->verts));
}
static double dt;
static HMM_Vec4 g_accel;
void emitter_step(emitter *e, double dt, transform2d *t) {
HMM_Vec4 g_accel = HMM_MulV4F((HMM_Vec4){cpSpaceGetGravity(space).x, cpSpaceGetGravity(space).y, 0, 0}, dt);
void parallel_step(emitter *e, struct scheduler *shed, struct sched_task_partition t, sched_uint thread_num)
{
for (int i = t.end-1; i >=0; i--) {
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);
//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;
@ -225,20 +113,10 @@ void parallel_step(emitter *e, struct scheduler *shed, struct sched_task_partiti
else if (query_point(e->particles[i].pos.xy))
arrdelswap(e->particles,i);
}
}
void emitter_step(emitter *e, double mdt) {
dt = mdt;
g_accel = HMM_MulV4F((HMM_Vec4){cpSpaceGetGravity(space).x, cpSpaceGetGravity(space).y, 0, 0}, dt);
if (arrlen(e->particles) == 0) return;
struct sched_task task;
scheduler_add(&sched, &task, parallel_step, e, arrlen(e->particles), arrlen(e->particles)/sched.threads_num);
scheduler_join(&sched, &task);
if (!e->on) return;
e->tte-=dt;
if (e->tte <= 0) {
emitter_spawn(e);
emitter_spawn(e, t);
e->tte = lerp(e->explosiveness, e->life/e->max,0);
}
}

View file

@ -7,6 +7,7 @@
#include "texture.h"
#include "anim.h"
#include "gameobject.h"
#include "render.h"
typedef struct particle {
HMM_Vec4 pos;
@ -23,9 +24,16 @@ typedef struct particle {
#define CLOUD 1
#define MESH 2
typedef struct par_vert {
HMM_Vec2 pos;
float angle;
float scale;
struct rgba color;
} par_vert;
typedef struct emitter {
struct particle *particles;
transform3d t;
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 */
@ -44,8 +52,6 @@ typedef struct emitter {
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 */
/* PARTICLE TYPE */
texture *texture;
/* ROTATION AND COLLISION */
int collision_mask; /* mask for collision */
float bounce; /* bounce back after collision */
@ -55,22 +61,15 @@ typedef struct emitter {
float persist_var;
/* TRAILS */
warpmask warp_mask;
int on;
double tte; /* time to emit */
sg_buffer buffer;
} emitter;
void particle_init();
emitter *make_emitter();
void emitter_free(emitter *e);
void start_emitter(emitter *e);
void stop_emitter(emitter *e);
void emitter_emit(emitter *e, int count);
void emitters_step(double dt);
void emitter_draw(emitter *e, gameobject *go);
void emitters_draw(HMM_Mat4 *proj);
void emitter_step(emitter *e, double dt);
void emitter_emit(emitter *e, int count, transform2d *t);
void emitter_step(emitter *e, double dt, transform2d *t);
void emitter_draw(emitter *e, sg_bindings bind);
#endif

View file

@ -18,9 +18,6 @@
#include "sokol/sokol_glue.h"
#include "stb_image_write.h"
#include "box.sglsl.h"
#include "shadow.sglsl.h"
#include "sokol/sokol_gfx.h"
#include "sokol_gfx_ext.h"
@ -31,7 +28,6 @@
HMM_Vec2 campos = {0,0};
float camzoom = 1;
sg_buffer sprite_quad;
sg_sampler std_sampler;
sg_sampler tex_sampler;
@ -127,14 +123,6 @@ void capture_screen(int x, int y, int w, int h, const char *path)
sg_pass_action pass_action = {0};
static struct {
sg_pass_action pass_action;
sg_pass pass;
sg_pipeline pipe;
sg_shader shader;
} sg_shadow;
void trace_apply_pipeline(sg_pipeline pip, void *data)
{
// YughSpam("Applying pipeline %u %s.", pip, sg_query_pipeline_desc(pip).label);
@ -228,20 +216,6 @@ void render_init() {
.buffer_pool_size = 1024
});
float quad[] = {
0,0,
1,0,
0,1,
1,1
};
sprite_quad = sg_make_buffer(&(sg_buffer_desc){
.data = quad,
.size = sizeof(quad),
.usage = SG_USAGE_IMMUTABLE,
.label = "sprite quad"
});
std_sampler = sg_make_sampler(&(sg_sampler_desc){});
tex_sampler = sg_make_sampler(&(sg_sampler_desc){
.min_filter = SG_FILTER_LINEAR,
@ -262,69 +236,6 @@ void render_init() {
pass_action = (sg_pass_action){
.colors[0] = {.load_action = SG_LOADACTION_CLEAR, .clear_value = c},
};
sg_gif.shader = sg_make_shader(box_shader_desc(sg_query_backend()));
sg_gif.pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = sg_gif.shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2,
[1].format = SG_VERTEXFORMAT_FLOAT2
}
},
.colors[0].pixel_format = SG_PIXELFORMAT_RGBA8,
.label = "gif pipe",
});
float crt_quad[] = {
-1, 1, 0, 1,
-1, -1, 0, 0,
1, -1, 1, 0,
-1, 1, 0, 1,
1, -1, 1, 0,
1, 1, 1, 1
};
float gif_quad[] = {
-1, 1, 0, 1,
-1, -1, 0, 0,
1, -1, 1, 0,
-1, 1, 0, 1,
1, -1, 1, 0,
1, 1, 1, 1
};
sg_limits ll = sg_query_limits();
printf("attribute limits %d\n", ll.max_vertex_attrs);
sg_gif.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(gif_quad),
.data = gif_quad,
.label = "gif vert buffer",
});
sg_gif.bind.fs.samplers[0] = std_sampler;
sg_crt.shader = sg_make_shader(crt_shader_desc(sg_query_backend()));
sg_crt.pipe = sg_make_pipeline(&(sg_pipeline_desc){
.shader = sg_crt.shader,
.layout = {
.attrs = {
[0].format = SG_VERTEXFORMAT_FLOAT2,
[1].format = SG_VERTEXFORMAT_FLOAT2
}
},
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
});
sg_crt.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.size = sizeof(crt_quad),
.type = SG_BUFFERTYPE_VERTEXBUFFER,
.usage = SG_USAGE_IMMUTABLE,
.data = SG_RANGE(crt_quad),
.label = "crt vert buffer",
});
}
HMM_Mat4 projection = {0.f};

View file

@ -15,6 +15,7 @@
#include "HandmadeMath.h"
#include "gameobject.h"
#include "transform.h"
#include "model.h"
#define RGBA_MAX 255
@ -33,7 +34,6 @@ extern HMM_Mat4 hudproj;
extern HMM_Mat4 useproj;
extern sg_pass_action pass_action;
extern sg_buffer sprite_quad;
extern sg_sampler std_sampler;
extern sg_sampler tex_sampler;

View file

@ -21,18 +21,18 @@ typedef union NoiseUnion {
noiseNDptr pn;
} genericNoise;
extern double Noise2D(double x, double y);
extern double Noise3D(double x, double y, double z);
extern double Noise4D(double x, double y, double z, double w);
double Noise2D(double x, double y);
double Noise3D(double x, double y, double z);
double Noise4D(double x, double y, double z, double w);
extern double GBlur1D(double stdDev, double x);
extern double GBlur2D(double stdDev, double x, double y);
double GBlur1D(double stdDev, double x);
double GBlur2D(double stdDev, double x, double y);
extern double Noise(genericNoise func, int len, double args[]);
double Noise(genericNoise func, int len, double args[]);
extern double TurbulentNoise(genericNoise func, int direction, int iterations, int len, double args[]);
extern double FractalSumNoise(genericNoise func, int iterations, int len, double args[]);
extern double FractalSumAbsNoise(genericNoise func, int iterations, int len, double args[]);
double TurbulentNoise(genericNoise func, int direction, int iterations, int len, double args[]);
double FractalSumNoise(genericNoise func, int iterations, int len, double args[]);
double FractalSumAbsNoise(genericNoise func, int iterations, int len, double args[]);
double octave_3d(double x, double y, double z, int octaves, double persistence);

View file

@ -63,7 +63,6 @@ void c_init() {
window_resize(sapp_width(), sapp_height());
phys2d_init();
render_init();
particle_init();
if (!JS_IsUndefined(c_start)) {
script_call_sym(c_start,0,NULL);
JS_FreeValue(js, c_start);

View file

@ -1,19 +0,0 @@
@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

View file

@ -1,3 +0,0 @@
void main(){
color = texture( myTextureSampler, UV );
}

View file

@ -1,11 +0,0 @@
void main(){
// Output position of the vertex, in clip space
// map [0..800][0..600] to [-1..1][-1..1]
vec2 vertexPosition_homoneneousspace = vertexPosition_screenspace - vec2(400,300); // [0..800][0..600] -> [-400..400][-300..300]
vertexPosition_homoneneousspace /= vec2(400,300);
gl_Position = vec4(vertexPosition_homoneneousspace,0,1);
// UV of the vertex. No special space for this one.
UV = vertexUV;
}

View file

@ -1,9 +0,0 @@
#version 330 core
layout (location = 0) out vec4 color;
in vec3 vcolor;
void main(void)
{
color = vec4(vcolor, 1.f);
}

View file

@ -1,17 +0,0 @@
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 color;
layout (std140) uniform Matrices {
mat4 projection;
mat4 view;
};
out vec3 vcolor;
void main()
{
gl_Position = projection * view * vec4(position, 1.0f);
vcolor = color;
}

View file

@ -1,136 +0,0 @@
@vs vs
in vec3 a_pos;
in vec2 a_tex_coords;
in vec3 a_norm;
out vec2 tex_coords;
out vec3 normal;
out vec3 frag_pos;
out vec4 frag_pos_light;
uniform vs_p {
uniform mat4 vp;
uniform mat4 model;
uniform mat4 proj;
uniform mat4 lsm;
};
void main() {
frag_pos = vec3(model * vec4(a_pos, 1.0));
gl_Position = proj * vp * vec4(frag_pos, 1.0);
tex_coords = a_tex_coords;
normal = mat3(transpose(inverse(model))) * a_norm;
frag_pos_light = lsm * vec4(frag_pos, 1.0);
}
@end
@fs fs
in vec2 tex_coords;
in vec3 normal;
in vec3 frag_pos;
in vec4 frag_pos_light;
out vec4 frag_color;
uniform texture2D diffuse;
uniform texture2D normmap;
uniform texture2D shadow_map;
uniform sampler smp;
uniform fs_p {
uniform vec3 point_pos;
uniform vec3 dir_dir;
uniform vec3 view_pos;
uniform vec3 spot_pos;
uniform vec3 spot_dir;
uniform vec2 shadow_dim;
};
/* Ambient light */
float amb_str = 0.3;
vec3 amb_color = vec3(1,1,1);
float spec_str = 0.5;
/* point */
float constant = 1;
float linear = 0.09;
float quad = 0.032;
/* spotlight */
float cutoff = 12.5; /* cutoff in radians */
float outer_cutoff = 17.5;
vec3 norm = vec3(0,0,0);
vec3 view = vec3(0,0,0);
float light_str(vec3 dir)
{
float d = max(dot(norm, dir), 0.0);
vec3 refl = reflect(-dir, norm);
float s = pow(max(dot(view,refl), 0.0), 32);
return s+d;
}
float shadow_calc(vec4 fg)
{
vec3 pc = fg.xyz / fg.w;
pc = pc * 0.5 + 0.5;
if (pc.z > 1.0)
return 0.0;
float closest_depth = texture(sampler2D(shadow_map,smp), pc.xy).r;
float cur_depth = pc.z;
vec3 light_dir = normalize(vec3(4,100,20) - frag_pos); /* light pos */
float bias = max(0.05 * (1 - dot(norm, light_dir)), 0.005);
return cur_depth - bias > closest_depth ? 1.0 : 0.0;
float s;
vec2 texel_size = 1 / shadow_dim;
for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
float pcf_depth = texture(sampler2D(shadow_map,smp), pc.xy + vec2(x,y) * texel_size).r;
s += cur_depth - bias > pcf_depth ? 1.0 : 0.0;
}
}
s /= 9.0;
return s;
}
void main() {
norm = normalize(normal);
view = normalize(view_pos - frag_pos);
float point_amt = light_str(normalize(point_pos-frag_pos));
float dist = length(point_pos - frag_pos);
float atten = 1.0 / (constant + linear * dist + quad * (dist*dist));
point_amt *= atten;
float dir_amt = light_str(normalize(-dir_dir));
vec3 spot_dir = normalize(spot_pos - frag_pos);
float theta = dot(spot_dir, normalize(-spot_dir));
float spot_amt = 0;
float epsilon = cutoff - outer_cutoff;
if (theta > cutoff) {
float intensity = clamp((theta - outer_cutoff)/epsilon,0.0,1.0);
spot_amt = light_str(spot_dir) * intensity;
}
vec4 mm = texture(sampler2D(diffuse,smp),tex_coords);
float shadow = shadow_calc(frag_pos_light);
vec3 res = mm.rgb * (amb_str + (point_amt + dir_amt) * (1 - shadow));
frag_color = vec4(res, mm.a);
}
@end
@program diffuse vs fs

View file

@ -1,44 +0,0 @@
@vs vs
in vec2 vertex;
in vec2 apos;
in float angle;
in vec2 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 *= 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